diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/connect-to-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/connect-to-a-workspace.mdx index d65065ada4..afe4241e81 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/connect-to-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/connect-to-a-workspace.mdx @@ -3,125 +3,76 @@ title: Connect to a Workspace sidebar_label: Connect to a Workspace --- -## Connect to a Workspace +Once a workspace is created, it is reachable over SSH at `WORKSPACE_NAME.devsy`. If you chose an IDE, Devsy opens it after the workspace starts. -Once a workspace is created, it is reachable through the SSH host `WORKSPACE_NAME.devsy`. If you chose an IDE, Devsy opens it after the workspace starts. +Pick the IDE with `--ide` when you start a workspace, or set a default for all workspaces: - -Change the default IDE globally with `devsy ide use vscode`, or per workspace with `devsy workspace up my-workspace --ide vscode`. - +```sh +devsy workspace up my-workspace --ide vscode +devsy ide use vscode +``` -### VS Code Browser +Run `devsy ide list` to see every supported IDE. -Devsy can open VS Code in a browser tab. It installs [openvscode-server](https://github.com/gitpod-io/openvscode-server) inside the workspace and tunnels a connection to it from localhost. Open the workspace in VS Code browser with: -``` -devsy workspace up my-workspace --ide openvscode -``` +### VS Code in the browser -To pick a different openvscode version: -``` -devsy workspace up my-workspace --ide openvscode --ide-option VERSION=v1.76.2 +Devsy installs [openvscode-server](https://github.com/gitpod-io/openvscode-server) in the workspace and tunnels to it from localhost. + +```sh +devsy workspace up my-workspace --ide openvscode ``` ### VS Code -Install the [remote ssh extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) and the [code CLI](https://code.visualstudio.com/docs/editor/command-line). Then start the workspace in VS Code with: -``` +Install the [Remote - SSH extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) and the [code CLI](https://code.visualstudio.com/docs/editor/command-line), then: + +```sh devsy workspace up my-workspace --ide vscode ``` - -If this doesn't work, use the regular SSH connection `WORKSPACE_NAME.devsy` to connect VS Code. - +If that fails, connect VS Code to `WORKSPACE_NAME.devsy` over SSH. -### JetBrains Suite (Goland, PyCharm, Intellij etc.) +### JetBrains IDEs -Install [JetBrains Gateway](https://www.jetbrains.com/remote-development/gateway/) and have a valid JetBrains subscription for your local IDE. Supported JetBrains IDEs: -* **CLion (clion)** -* **Goland (goland)** -* **PyCharm (pycharm)** -* **Intellij (intellij)** -* **PhpStorm (phpstorm)** -* **WebStorm (webstorm)** -* **Rider (rider)** -* **RubyMine (rubymine)** +Install [JetBrains Gateway](https://www.jetbrains.com/remote-development/gateway/). You need a license for the IDE you use. Start the workspace with the IDE name, for example: -Start your workspace with: -``` +```sh devsy workspace up my-workspace --ide goland ``` -Devsy installs the GoLand server binary into the workspace and opens JetBrains Gateway. After installation, the Gateway SSH dialog appears pre-filled - click **Check Connection and Continue** to start the IDE inside the workspace. - -To pick a different IDE version: -``` -devsy workspace up my-workspace --ide goland --ide-option VERSION=2022.3.3 -``` +Devsy installs the IDE server in the workspace and opens Gateway. Click **Check Connection and Continue** in the prefilled SSH dialog. If that fails, connect Gateway to `WORKSPACE_NAME.devsy` over SSH. - -If this doesn't work, use the SSH host `WORKSPACE_NAME.devsy` to connect your JetBrains IDE. - - - -Fleet only works by manually adding an SSH connection to `WORKSPACE_NAME.devsy`. - +Fleet works only through a manually added SSH connection to `WORKSPACE_NAME.devsy`. ### SSH -When a workspace is created, Devsy adds an entry for `WORKSPACE_NAME.devsy` to `~/.ssh/config`. Connect with: -``` +Devsy adds a `WORKSPACE_NAME.devsy` entry to `~/.ssh/config` when it creates a workspace. + +```sh ssh WORKSPACE_NAME.devsy ``` -Any IDE that supports remote development over SSH can also use this host. - -### Devsy CLI +Any IDE with remote SSH support can use this host. Without an `ssh` client, use the CLI: -If you don't have `ssh` installed or can't connect through an IDE, use the Devsy CLI: -``` +```sh devsy workspace ssh my-workspace -``` - -Run a command non-interactively: -``` devsy workspace ssh my-workspace --command "echo Hello World" ``` -## IDE Commands - -Configure how Devsy opens workspaces with these commands. +## IDE options -### Configure IDE Options +Each IDE has options such as the version. List and change them with: -Each IDE supports options like version and download path. List them with: -``` +```sh devsy ide get openvscode -``` - -Change an option with: -``` devsy ide set openvscode -o VERSION=v1.76.2 ``` -### Change Default IDE - -Set the default IDE Devsy uses to open workspaces: -``` -devsy ide use vscode -``` - -### List supported IDEs - -List every IDE Devsy supports: -``` -devsy ide list -``` +You can also set an option for a single workspace with `--ide-option VERSION=...` on `devsy workspace up`. ## Desktop shortcuts -Devsy Desktop ships a command palette and section shortcuts for fast navigation: - -- `Cmd/Ctrl + K` - open the command palette (search workspaces, providers, machines, and pages). -- `Cmd/Ctrl + N` - start the New Workspace wizard. -- `Cmd/Ctrl + 1` through `Cmd/Ctrl + 8` - jump to Dashboard, Workspaces, Providers, Machines, Contexts, Terminals, SSH Keys, and Settings. -- `Esc` - close the active sheet, dialog, or palette (where supported). +- `Cmd/Ctrl + K` opens the command palette. +- `Cmd/Ctrl + N` starts the New Workspace wizard. +- `Cmd/Ctrl + 1` to `8` jumps between the main sections. +- `Esc` closes the open sheet, dialog, or palette. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/continuous-integration.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/continuous-integration.mdx index 6021805201..afaca3facc 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/continuous-integration.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/continuous-integration.mdx @@ -3,13 +3,9 @@ title: Continuous Integration sidebar_label: Continuous Integration --- -## Continuous Integration +`devsy ci` builds an ephemeral devcontainer, runs a command in it, and deletes the workspace afterwards. Use it to check that your `devcontainer.json` still builds and your tests pass inside it. -`devsy ci` builds an ephemeral devcontainer, runs a command inside it, and tears -the workspace down afterwards. It lets you verify that your `devcontainer.json` -still builds. - -### How it works +## How it works 1. Resolves a workspace from the current directory (or a given source). 2. Builds and starts the devcontainer (equivalent to `devsy workspace up`, without @@ -21,7 +17,7 @@ still builds. A non-zero exit from the command propagates as the exit code of `devsy ci`, so a failing test or build fails the CI job. -### Usage +## Usage ```sh devsy ci [flags] [workspace-path|workspace-name] -- [args...] @@ -54,27 +50,16 @@ devsy ci --keep -- ./run-integration-tests.sh ### Common flags -| Flag | Description | -| --- | --- | -| `--run-cmd` | Shell command run inside the container via `sh -c` (alternative to an explicit argv after `--`). | -| `--remote-env KEY=VALUE` | Set an environment variable in the container at run time. Repeatable. | -| `--keep` | Keep the workspace instead of tearing it down. | -| `--devcontainer` | Select the devcontainer config source: `none`, `image:`, `id:`, or a path to a `devcontainer.json`. | -| `--no-cache` | Build without using the cache. | -| `--cache-from` | Reuse a pre-built image as a build cache source. Repeatable. | -| `--platform` | Run the container under a specific platform via emulation (e.g. `linux/amd64`). | -| `--workspace-env KEY=VALUE` | Env variables available at build and lifecycle time (not just at run time). Repeatable. | -| `--workspace-env-file` | File(s) of `KEY=VALUE` build/lifecycle env variables. | -| `--init-env KEY=VALUE` | Env variables injected during workspace initialization. Repeatable. | -| `--secrets-file` | JSON file (`{"KEY":"value"}`) of secrets injected into lifecycle commands. | -| `--feature-secrets-file` | JSON file of secret values for features. | -| `--secret` | Stored Devsy secret to inject, as `NAME[,type=env\|mount][,target=X]`. Repeatable. | -| `--env` | Stored Devsy env var to inject, as `NAME[=TARGET]`. Repeatable. | -| `--build-secret` | Stored Devsy secret exposed to the build via BuildKit. Repeatable. | -| `--git-token` | Stored Devsy secret with an access token for cloning a private HTTP repository. | -| `--git-token-username` | Username for `--git-token` (default inferred from the repo host). | - -### Pre-building and pushing images +Run `devsy ci --help` for the full list. The most used: + +- `--keep` keeps the workspace instead of deleting it. +- `--remote-env KEY=VALUE` sets an environment variable in the container at run time. Repeatable. +- `--devcontainer` picks the config: `none`, `image:`, `id:`, or a path to a `devcontainer.json`. +- `--cache-from` and `--no-cache` control the image build cache. +- `--platform` runs the container under another platform, such as `linux/amd64`. +- `--secret`, `--env`, `--build-secret`, and `--git-token` inject stored Devsy secrets and variables. See [Secrets](./secrets.mdx). + +## Pre-building and pushing images `devsy ci` focuses on running a command. To pre-build and publish a devcontainer image for reuse as a build cache, use `devsy workspace build`: @@ -86,7 +71,7 @@ devsy workspace build --repository ghcr.io/my-org/my-devcontainer --tag latest - Downstream CI jobs can then reference that image via `--cache-from` to speed up builds. -### GitHub Actions +## GitHub Actions Install the CLI, configure the docker provider, then run `devsy ci`: diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/create-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/create-a-workspace.mdx index 117cec0862..afe852549f 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/create-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/create-a-workspace.mdx @@ -3,223 +3,127 @@ title: Create a Workspace sidebar_label: Create a Workspace --- -A workspace in Devsy is a containerized development environment that holds a project's source code along with the dependencies needed to work on it, such as a compiler and debugger. The underlying environment where the container runs is created and managed through a Devsy provider. This gives every engineer a consistent development experience wherever the container runs - a remote machine in a public cloud, localhost, or a Kubernetes cluster. +A workspace is a containerized development environment that holds a project's source and the tools needed to work on it. A [provider](../managing-providers/what-are-providers.mdx) creates the environment it runs in. -To configure the development container, Devsy reuses the [devcontainer.json](https://containers.dev/) specification, which is also used by other popular tools such as [VS Code dev containers](https://code.visualstudio.com/docs/devcontainers/containers) and [GitHub Codespaces](https://github.com/features/codespaces). This means any project that already uses this configuration can spin up a workspace in Devsy with no extra setup. If no configuration is found, Devsy detects the project's programming language and provides an appropriate template. +Devsy uses the [devcontainer.json](https://containers.dev/) specification, which VS Code dev containers and GitHub Codespaces also use, so a project that already has one needs no extra setup. If there is none, Devsy detects the project's language and offers a template. -A workspace can be stopped and restarted without losing its state, so you can install additional programs or change configuration without reconfiguring the container. Depending on the provider, Devsy also detects when a workspace is no longer in use and shuts down idle resources to keep infrastructure costs down. +A workspace keeps its state when you stop and restart it. Once it exists, it is reachable over SSH at `WORKSPACE_NAME.devsy`, and Devsy can open it in a local IDE. -## Create a Workspace +## Create a workspace -Create workspaces from the Devsy CLI or the Desktop app. A workspace's source can be a Git repository, a local path, or a Docker image (e.g. `golang:latest`). - -Once created, the workspace is reachable through the SSH host `WORKSPACE_NAME.devsy`, or Devsy can open it in a local IDE like VS Code or IntelliJ. - - -A workspace is defined by a `devcontainer.json`. If none exists, Devsy detects the project's language and picks a matching template. - +The source can be a Git repository, a local folder, or an image such as `golang:latest`. ### Devsy Desktop -Open the Workspaces view and click **Create** to launch the wizard. It walks through five steps: - -1. **Provider** - pick an initialized provider. Cannot be changed later. If none exists, the wizard offers to add one. -2. **Source** - choose a Quick Start template, browse the image catalog, or enter a custom Git URL / image / local path. **Show advanced options** reveals: - - Ref Type and value (branch, commit, or PR number) for Git sources. - - Project subfolder within the repo. - - Open folder in container (where the editor opens). - - Dev container config path (override `.devcontainer/devcontainer.json` location). - - Prebuild repository for cached images. -3. **IDE** - pick one or more IDEs to open the workspace with. Optional; defaults to none. -4. **Review** - adjust the auto-derived workspace name and confirm the configuration. If the chosen image has no build for your machine architecture, the Review step shows a compatibility warning and a **Run under emulation** toggle. -5. **Launch** - Devsy creates the workspace and streams progress. A 10-minute watchdog cancels the launch if it stalls. The chosen IDE opens on success. - - -Under the hood, the Desktop Application will call the CLI command `devsy workspace up REPOSITORY` - - - -You can set the location of your devsy home by passing the `--home={home_path}` flag, -or by setting the env var `DEVSY_HOME` to your desired home directory. +Open **Workspaces** and click **Create**. The wizard has five steps: -This can be useful if you are having trouble with a workspace trying to mount to a windows location when it should be mounting to a path inside the WSL VM. +1. **Provider.** Pick an initialized provider. You cannot change it later. +2. **Source.** Pick a template or an image, or enter a Git URL, image, or local path. **Show advanced options** lets you set the branch, commit, or PR, a project subfolder, the folder to open, the `devcontainer.json` path, and a prebuild repository. +3. **IDE.** Optional. The default is none. +4. **Review.** Check the workspace name and configuration. If the image has no build for your architecture, you can turn on **Run under emulation**. +5. **Launch.** Devsy creates the workspace and streams progress, then opens your IDE. -For example: setting `--home=/mnt/c/Users/MyUser/` will result in a workspace path of something like `/mnt/c/Users/MyUser/.devsy/contexts/default/workspaces/...` - +The desktop app runs `devsy workspace up` for you. ### Devsy CLI -[Install the Devsy CLI](../getting-started/install.mdx#install-devsy-cli) and add a provider to host the workspace (such as local docker): -``` -# Add a provider if you haven't already +[Install the CLI](../getting-started/install.mdx#install-devsy-cli) and add a provider, for example Docker: + +```sh devsy provider add docker ``` -#### Git Repository - -Start a new workspace from a Git repository: +**Git repository** -``` -# Create from Git repository +```sh devsy workspace up github.com/microsoft/vscode-remote-try-node ``` -Append a commit hash, branch, or pull request slug to the URL to check out a specific ref: -``` -Branch: devsy workspace up github.com/microsoft/vscode-remote-try-node@main -Commit: devsy workspace up github.com/microsoft/vscode-remote-try-node@sha256:15ba80171af11374143288fd3d54898860107323 -PR: devsy workspace up github.com/microsoft/vscode-remote-try-node@pull/108/head # Only works for GitHub! -``` - - -Devsy forwards your git credentials to the remote machine so private repositories work too. - - - -Pass `--id` to override the workspace name. This lets you spin up multiple workspaces from one repository. - +Add `@` and a ref to pick a branch, commit, or pull request: +```sh +devsy workspace up github.com/microsoft/vscode-remote-try-node@main +devsy workspace up github.com/microsoft/vscode-remote-try-node@sha256:15ba80171af11374143288fd3d54898860107323 +devsy workspace up github.com/microsoft/vscode-remote-try-node@pull/108/head # GitHub only +``` -#### Local Path +Devsy forwards your git credentials, so private repositories work. Use `--id` to name the workspace, which lets you create several from one repository. -Create a workspace from a local folder: +**Local folder** -``` -# Create from a local path +```sh devsy workspace up ./path/to/my-folder ``` -Devsy syncs the folder onto the remote machine and builds the dev environment from the `devcontainer.json`. - -### Control local-folder uploads with `.devsyignore` - -Place `.devsyignore` at the root of your local workspace source to choose which -files Devsy uploads when a provider streams the folder, including Kubernetes. -The CLI and Desktop use the same transfer policy. For example: - -```text -big/ -**/node_modules/ -docs/*.tgz -build/ -!build/keep.txt -``` +Devsy copies the folder to the provider and builds from its `devcontainer.json`. See [.devsyignore](#devsyignore) to leave files out. -Rules use [Docker ignore syntax](https://docs.docker.com/build/concepts/context/#dockerignore-files), -including `*`, `?`, character classes, `**`, and ordered `!` exceptions. Paths -are relative to the workspace source root; the last matching rule wins. -`build/` excludes `build` and its descendants while retaining `buildSrc`. -`docs/*.tgz` excludes archives directly inside `docs`, while `**/node_modules/` -excludes dependency folders at any depth. A rule can exclude `.devsyignore` itself. - -A missing ignore file permits the entire source to upload. An empty file is valid. -An existing file that cannot be read or contains an invalid pattern stops the -upload before any archive data is sent. Correct the file identified in the error -and retry. This replaces the previous silent, unfiltered fallback. Debug logs -identify the ignore file and rule count without listing the rules. - -Workspace rules do not filter additional configured bind mounts, even when they -refer to the same source directory at a different container target. Configure -those mounts deliberately: `.devsyignore` does not prevent their contents from -being transferred. Local Docker bind mounts expose the host folder directly and -do not remove ignored files. Remote Git clones also do not use this upload policy. -`.gitignore` and `.dockerignore` are not substituted for `.devsyignore`; Docker -image builds continue to use their own build-context rules. - -Devsy preserves only verified artifacts generated for the current Dockerless build, -including files inside a nested build context, when they are needed for startup. -Other folders named `.devsy-internal` remain subject to the rules. A required -generated context outside the authorized workspace source produces an error. - -For a workspace with a large `big/blob.bin`, dependency folders, and packaged -archives, the example rules avoid transferring those files and reduce remote -disk usage. The reduction depends on your source contents, rather than a fixed -upload duration. [Workspace snapshots](./workspace-snapshots.mdx) also distinguish -the workspace volume from independent bind mounts. - -#### Docker Image - -Create a workspace from a Docker image: +**Image** -``` -# Create from a docker image +```sh devsy workspace up ghcr.io/my-org/my-repo:latest ``` -Devsy generates the following `.devcontainer.json`: -``` -{ - "image": "ghcr.io/my-org/my-repo:latest" -} -``` +Devsy generates a `devcontainer.json` that names the image. To run an image built for another architecture, add `--platform linux/amd64`. Emulation can be much slower, so prefer multi-arch images. -##### Run under a different platform +The desktop app also has a catalog of ready-made images and flags any that do not fit your machine. -Pass `--platform` to run the container under a non-native architecture (via QEMU emulation on Docker). This is useful for images that only ship `linux/amd64` when you're on Apple Silicon. +**Existing container** -``` -devsy workspace up ghcr.io/my-org/my-repo:latest --platform linux/amd64 +```sh +devsy workspace up my-workspace --source container:$CONTAINER_ID ``` - -Emulated containers can be significantly slower than native ones. Prefer multi-arch images when available. - +Only the `docker` provider supports this, and `--recreate` is rejected for these workspaces. -##### Image catalog (Desktop) + +To change where Devsy keeps its data, pass `--home=PATH` or set `DEVSY_HOME`. This helps on WSL when a workspace tries to mount a Windows path instead of a path inside WSL. + -Devsy Desktop ships a curated catalog of pre-built devcontainer images. The Source step of the workspace wizard surfaces them in an image picker and flags incompatible images (e.g. an `arm64`-only image on an `amd64` host). The CLI accepts any of these images as a `--source` or positional argument. +## .devsyignore -#### Existing local container +Put a `.devsyignore` file in the root of a local workspace folder to leave files out of the upload when the provider streams the folder, as Kubernetes does. It uses [Docker ignore syntax](https://docs.docker.com/build/concepts/context/#dockerignore-files). Paths are relative to the folder, and the last matching rule wins. -Bind a workspace to a container that is already running: -``` -devsy workspace up my-workspace --source container:$CONTAINER_ID +```text +big/ +**/node_modules/ +docs/*.tgz +build/ +!build/keep.txt ``` -Only the `docker` provider supports this. - - -`--recreate` is rejected on a workspace backed by an existing container. - +- A missing or empty file uploads everything. +- An unreadable file or an invalid pattern stops the upload with an error that names the file. +- It does not apply to extra bind mounts, to local Docker bind mounts, to remote Git clones, or to image builds, which use their own rules. `.gitignore` and `.dockerignore` are not used in its place. ## Inspect a workspace -`devsy workspace describe ` prints a workspace's full configuration plus its live state. By default it renders a `Field | Value` table; pass `--result-format json` for machine-readable output (Devsy Desktop uses the JSON form). - ```sh devsy workspace describe my-workspace -devsy workspace describe my-workspace --result-format json ``` -Other useful inspection commands: - -- `devsy workspace status ` - quick state check (`Running`, `Stopped`, `NotFound`). -- `devsy workspace logs ` - stream the agent logs from the container. -- `devsy workspace ping ` - verify the agent is reachable through the tunnel. -- `devsy workspace troubleshoot ` - bundle diagnostics for issue reports. +This prints the configuration and live state. Add `--result-format json` for scripts. Other commands: -## Recreating a workspace +- `devsy workspace status ` shows whether it is running or stopped. +- `devsy workspace logs ` streams the agent logs. +- `devsy workspace ping ` checks that the agent is reachable. +- `devsy workspace troubleshoot ` bundles diagnostics for an issue report. -Recreating a workspace re-applies changes from the `devcontainer.json` or its `Dockerfile`. Use this after editing the devcontainer or pulling new changes that affect the dev environment. If a prebuild repository is configured, Devsy looks for the updated image there first and falls back to building locally. +## Recreate a workspace -Only changes inside the project path or mounted volumes survive a recreate. **Everything else in the container is lost.** - -### Devsy CLI +Recreating applies changes to `devcontainer.json` or its Dockerfile. If a prebuild repository is configured, Devsy looks there for the new image first. -Rebuild an existing workspace: -``` +```sh devsy workspace up my-workspace --recreate ``` -## Resetting a workspace + +Only the project folder and mounted volumes survive. Everything else in the container is lost. + -Reset rebuilds the workspace from a clean slate - it pulls the latest Git changes or re-uploads your local folder. Use it instead of `--recreate` when you need a full restart. +## Reset a workspace -**A reset preserves nothing.** +A reset starts from a clean slate. It pulls the latest Git changes or uploads your local folder again, and it keeps nothing. -### Devsy CLI - -Reset an existing workspace: -``` +```sh devsy workspace up my-workspace --reset ``` diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/credentials.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/credentials.mdx index 0fac1b0ac2..be2bb07a96 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/credentials.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/credentials.mdx @@ -3,45 +3,40 @@ title: Reuse local credentials sidebar_label: Reuse local credentials --- -Devsy will automatically make certain local credentials available inside of the development container through a [credentials helper](https://git-scm.com/docs/gitcredentials). -This allows you to reuse existing local credentials in a safe manner within the development container without explicitly configuring them inside each workspace. -Currently Devsy supports this feature for git credentials and docker credentials. +Devsy makes some of your local credentials available inside the dev container, so you do not configure them in each workspace. It supports git credentials, Docker registry credentials, and GPG keys. - -Do not enable credential injection or SSH agent forwarding for untrusted repositories, or for any `devcontainer.json` you have not reviewed. Anything that runs inside the container - including lifecycle commands and features defined in `devcontainer.json` - can use the forwarded credentials. + +Code that runs in the container, including lifecycle commands and features from `devcontainer.json`, can use these credentials. Do not enable them for repositories or `devcontainer.json` files you have not reviewed. -SSH agent forwarding never exposes your private key to the container, but it is not a full sandbox boundary: anyone with access to the forwarded agent socket inside the container can request signatures, and therefore authenticate as you against any remote service the key is trusted by, for as long as the workspace runs. A malicious or compromised `devcontainer.json` can use this to push, pull, or otherwise act with your identity, even though it can never exfiltrate the key itself. The same caution applies to injected git/docker credentials: they let code in the container act with your access. +SSH agent forwarding never exposes your private key. It does let anything in the container request signatures, and so act as you against any service the key can access, for as long as the workspace runs. -## Git credentials +## Git -Devsy will make https credentials available inside the dev container through a [git credentials helper](https://git-scm.com/docs/gitcredentials). ssh credentials are available through agent-forwarding that will be configured automatically on the ssh configuration for the workspace. +Devsy provides HTTPS credentials through a [git credential helper](https://git-scm.com/docs/gitcredentials). SSH credentials work through agent forwarding, which Devsy sets up in the workspace's SSH config. To turn injection off for all workspaces: -If you don't want Devsy to inject the credentials, you can disable that via the following command for all workspaces: -``` +```sh devsy context set default -o SSH_INJECT_GIT_CREDENTIALS=false ``` -## Docker credentials +## Docker -Devsy will make docker registry credentials available inside the dev container through a [docker credentials helper](https://docs.docker.com/engine/reference/commandline/login/#credential-helpers). This allows you to pull and push images from and to private registries from within the dev container. +Devsy provides registry credentials through a [Docker credential helper](https://docs.docker.com/engine/reference/commandline/login/#credential-helpers), so you can pull and push private images from the container. To turn it off for all workspaces: -If you don't want Devsy to inject the credentials, you can disable that via the following command for all workspaces: -``` +```sh devsy context set default -o SSH_INJECT_DOCKER_CREDENTIALS=false ``` -## GPG credentials +## GPG -Devsy will make gpg keys available inside the dev container through an ssh tunnel. This allows you to sign commits from inside the workspace. +Devsy can forward your GPG keys into the container over the SSH tunnel, so you can sign commits there. To turn it on for all workspaces: -To have Devsy inject the gpg keys, enable it via the following command for all workspaces: -``` +```sh devsy context set default -o GPG_AGENT_FORWARDING=true ``` -Or when creating a workspace using: +Or for one workspace: -``` +```sh devsy workspace up --ssh-gpg-forwarding my-workspace ``` diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-json.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-json.mdx index b43eeff9a2..4d296f6d73 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-json.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-json.mdx @@ -3,77 +3,52 @@ title: devcontainer.json sidebar_label: devcontainer.json --- -Devsy uses the [open `devcontainer.json` standard](https://containers.dev/) to allow users to customize their development containers. -Development containers are Docker containers that provide a user with a fully featured development environment. -Within Devsy, this container is created based on the underlying provider either locally, in a remote virtual machine or even in a Kubernetes cluster. -Devsy makes sure that no matter where you use this configuration the developer experience stays the same. - -You can configure this development container for a certain Git repository so that each workspace gives you a custom development environment -completely configured with the tooling and runtimes you need for working on that specific project. -If Devsy doesn't find any configuration for the project it will automatically detect the programming language and provide a sane default configuration. - - -The same format is used by VS Code for their development containers and by GitHub for their Codespaces. -This makes it easy to reuse existing configurations and tooling around this standard within Devsy. - +Devsy uses the [open `devcontainer.json` standard](https://containers.dev/) to define the development container for a project. Because VS Code and GitHub Codespaces use the same format, existing configurations work in Devsy, and the container behaves the same on every provider. - -This page introduces working with devcontainers. For more detail, see: -* [DevContainer Reference](https://containers.dev/implementors/json_reference/) -* [VS Code DevContainer Documentation](https://code.visualstudio.com/docs/devcontainers/create-dev-container) -* [GitHub Codespaces Documentation](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#devcontainerjson) - +If a project has no configuration, Devsy detects the language and uses a default. -## devcontainer.json +For the full format, see the [reference](https://containers.dev/implementors/json_reference/), the [VS Code documentation](https://code.visualstudio.com/docs/devcontainers/create-dev-container), and the [Codespaces documentation](https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers#devcontainerjson). -The primary file to configure your workspace is the `devcontainer.json`, that lives in the `.devcontainer` sub-folder of your project. -This file includes information on what frameworks, tools, VS Code extensions and port-forwarding should be used during development. -The file also usually references a Dockerfile or a Docker image to use as the base for the development environment. -If Devsy doesn't find any configuration for the project, it will automatically detect the programming language and provide a sane default configuration. +## Where the file lives -The `devcontainer.json` can be located at the following places within your project: -* `.devcontainer/devcontainer.json` -* `.devcontainer.json` -* `.devcontainer/my-other-folder/devcontainer.json` +Devsy looks for one of: -You can specify a specific file to use via the `--devcontainer-path` CLI flag: -``` -devsy workspace up github.com/my-org/my-repo --devcontainer-path ./my-git-path-to/a-devcontainer-json-file.json -``` +- `.devcontainer/devcontainer.json` +- `.devcontainer.json` +- `.devcontainer//devcontainer.json` -### Existing workspace selection +To use a specific file, pass its path: -Devsy remembers the effective devcontainer configuration for an existing workspace so that restart and other lifecycle operations keep the same environment. If fresh project discovery later prefers a different config, a legacy workspace warns about the selection drift and continues using its previously resolved config. Devsy does not switch the workspace implicitly. +```sh +devsy workspace up github.com/my-org/my-repo --devcontainer-path ./path/to/devcontainer.json +``` -To adopt another config intentionally, run `devsy workspace up --recreate --devcontainer ""` or select a named profile with `--recreate --devcontainer "id:"`. The choice is persisted for subsequent lifecycle operations. +A configuration can inherit from other files with `extends`, which takes a path or a list of paths. Keep files the configuration depends on inside its folder. -A `devcontainer.json` is not able to import or inherit any settings from other `devcontainer.json` files, so make sure all dependent files and folders are available within the configuration subdirectory. +### Existing workspaces -### Using a Dockerfile +Devsy remembers which configuration a workspace uses. If a later search would pick a different file, Devsy warns and keeps the old one. To switch on purpose, recreate the workspace: -In order to use a Dockerfile for your configuration, you can specify the following within your `devcontainer.json`: +```sh +devsy workspace up --recreate --devcontainer "" +devsy workspace up --recreate --devcontainer "id:" ``` + +The choice is saved for later runs. + +## Dockerfile + +```json { "build": { "dockerfile": "Dockerfile" - }, - ... + } } ``` -And the Dockerfile could look like this: -``` -FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-16-buster - -# Install extra tooling into the environment via the following command -RUN apt-get update && apt-get install vim -``` - -For more information about how to write Dockerfiles, please visit the [official documentation](https://docs.docker.com/engine/reference/builder/) - -### Using Docker Compose +## Docker Compose -To use Docker Compose for your configuration, reference one or more compose files via `dockerComposeFile` and pick the service Devsy should treat as the dev container: +Point `dockerComposeFile` at one or more compose files and choose the service to use as the dev container: ```json { @@ -82,33 +57,22 @@ To use Docker Compose for your configuration, reference one or more compose file } ``` -#### Compose project name +Devsy names the compose project the same way Docker Compose does, so it reuses a project that is already running. In order: -Devsy resolves the Docker Compose project name using the same precedence Docker Compose itself uses, so `devsy workspace up` reuses an already-running compose project instead of spawning a separate one: +1. `COMPOSE_PROJECT_NAME` in your shell. +2. `COMPOSE_PROJECT_NAME` in an `.env` file, in the devcontainer folder, the workspace root, or a compose file's folder. +3. The top-level `name:` in the compose files. The last file that sets it wins. +4. A name derived from the workspace. -1. `COMPOSE_PROJECT_NAME` set in the current shell session. -2. `COMPOSE_PROJECT_NAME` from an `.env` file - checked in the devcontainer config directory (e.g. `.devcontainer/.env`), the workspace root, and each resolved compose file's own directory. -3. The top-level `name:` field in the compose files (when multiple files are given, the last one that declares it wins). -4. Otherwise, a name derived from the workspace, sanitized for Docker Compose. +The `name` field in `devcontainer.json` is only a display name and never names the compose project. - -`devcontainer.json`'s `name` field is a display name for the UI (per the [Dev Containers spec](https://containers.dev/implementors/json_reference/#general-fields)) and is never used to name the Docker Compose project. To reuse an existing compose project, set `COMPOSE_PROJECT_NAME` (shell or `.env`) or a top-level `name:` in your compose file - the same options [VS Code documents](https://code.visualstudio.com/remote/advancedcontainers/set-docker-compose-project-name) for this purpose. - - - -When using a `docker-compose.yml`-based `devcontainer.json` (via `dockerComposeFile`), a `platform` pin set on the compose service (or under `build.platforms`) is correctly honored during the build, including on arch-restricted base images. - +A custom `DOCKER_HOST` set for the Docker provider is passed to the `docker compose` commands Devsy runs. -### Add Additional DevContainer Features +## Features -`devcontainer.json` allows you to reuse certain predefined features within your configuration. -You can think of features as reusable Dockerfile parts that will be merged into your Dockerfile upon creation. -This makes it easy to reuse functionality such as `docker-in-docker` or install extra tooling such as `node` or `kubectl` without having to look up the exact Dockerfile commands. -A list of available features can be found [here](https://containers.dev/features). +[Features](https://containers.dev/features) are reusable pieces that Devsy merges into your Dockerfile, such as `docker-in-docker` or `kubectl`. -Devsy is able to add HTTP headers when downloading -feature archives as tar.gz files. To do so, add the needed headers in the `customizations` -field of the `devcontainer.json` file as follows: +To send HTTP headers when downloading a feature archive, set them under `customizations`: ```json { @@ -126,58 +90,44 @@ field of the `devcontainer.json` file as follows: } ``` -## devcontainer.json Development Flow +## Applying changes + +After you edit the configuration, apply it without deleting the workspace: -When working on the `devcontainer.json` itself, it's important to understand when Devsy will apply new configuration. +```sh +devsy workspace up my-workspace --recreate +``` -A naive approach would be to delete and recreate a workspace after each `devcontainer.json` change (which obviously works), but Devsy allows you to make changes to the configuration on the fly and reapply them via `devsy workspace up my-workspace --recreate`. -This will apply **ALL** new configurations including Dockerfile changes as well as new mounts, new features or any other configuration that is not included in the above command. Devsy will only replace the existing running container if the command has succeeded, so if there is a mistake in the new configuration, the existing workspace should not be impacted. +This applies all changes, including the Dockerfile, mounts, and features. Devsy replaces the running container only if the rebuild succeeds, so a mistake does not break the existing workspace. - -Changes in the overlay layer of the container, which means all changes to non-volumes will be lost. Changes within the project path and all other mounted paths will be preserved. + +Changes outside volumes are lost. The project folder and other mounted paths are kept. -## Environment Variables in devcontainer.json +## Environment variables in devcontainer.json -If you're combining SSH provider with using environment variables in your `.devcontainer.json`, -please follow the steps below to make sure that your environment variables are properly set on the remote machine. +When you use `${localEnv:NAME}` in `devcontainer.json` with the SSH provider, the variable has to reach the remote machine. -### Steps +1. Reference the variable in `devcontainer.json`: -1. Prepare a `.devcontainer.json` to include `${localEnv:}` directive.
- Example `.devcontainer.json`: -```json -{ - "name": "Node.js", - "image": "mcr.microsoft.com/devcontainers/javascript-node:${localEnv:IMAGE_VERSION}" -} -``` + ```json + { + "name": "Node.js", + "image": "mcr.microsoft.com/devcontainers/javascript-node:${localEnv:IMAGE_VERSION}" + } + ``` -2. Prepare an entry in a local `.ssh/config` to include `SetEnv =` directive.
- Example `.ssh/config`: -```console -Host - SetEnv IMAGE_VERSION=0-18-bullseye -``` +2. Send it from your local `~/.ssh/config`: -3. Log to your remote machine and in the `/etc/ssh/sshd_config` add an entry `AcceptEnv `.
- For example: -```console -AcceptEnv IMAGE_VERSION -``` + ``` + Host + SetEnv IMAGE_VERSION=0-18-bullseye + ``` -4. Restart SSH service on your remote machine.
-For example on Debian Linux: -```console -systemctl restart ssh.service -``` +3. On the remote machine, add `AcceptEnv IMAGE_VERSION` to `/etc/ssh/sshd_config` and restart the SSH service. -5. Run a `devsy workspace up` command, specifying the SSH provider: +4. Start the workspace: -```console -devsy workspace up --provider ssh --ide=none -``` - - -If your Docker provider is configured with a custom `DOCKER_HOST` (or other Docker environment variables), that environment is forwarded into the `docker compose` commands Devsy runs for a `dockerComposeFile`-based `devcontainer.json`, so the build and run steps consistently hit the same daemon as your other Docker commands. - + ```sh + devsy workspace up --provider ssh --ide=none + ``` diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-overlay.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-overlay.mdx index b1c3e17411..49c4691782 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-overlay.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/devcontainer-overlay.mdx @@ -3,34 +3,35 @@ title: Devcontainer overlays sidebar_label: Devcontainer overlays --- -Use `--devcontainer-overlay` to layer a second `devcontainer.json` over the config selected for a workspace: +`--devcontainer-overlay` layers a second `devcontainer.json` over the config selected for a workspace: ```sh devsy workspace up --devcontainer-overlay ./devcontainer/overlay.json ``` -The overlay participates in build planning before substitution and image creation. Supported build selectors are `image`, `dockerFile`, `context`, `build`, `dockerComposeFile`, `service`, and `runServices`. `initializeCommand`, `features`, and `overrideFeatureInstallOrder` also participate before the build. The primary config remains the effective origin; paths to assets declared in the overlay and local features are resolved relative to the file that declares them. +The overlay is applied during build planning, before substitution and image creation. It supports these fields: `image`, `dockerFile`, `context`, `build`, `dockerComposeFile`, `service`, `runServices`, `initializeCommand`, `features` and `overrideFeatureInstallOrder`. It does not enable arbitrary config replacement. The primary config stays the effective origin. Paths inside the overlay, including local features, are relative to the file that declares them. -## Replacement and clearing +## How fields combine -Fields absent from an overlay leave the primary value in place when both configs select the same build type. Selecting a different build type (image, Dockerfile, or Compose) clears incompatible fields from the previous type before applying the new selector. For example, an overlay that selects Compose can replace a primary image config without retaining its image selector. +- **Same build type.** Fields missing from the overlay keep the primary value. +- **Different build type** (image, Dockerfile or Compose). Fields from the previous type are cleared before the new selector applies. An overlay that selects Compose can replace a primary image config without keeping its image. +- **`build`.** `args` merge by key, with overlay keys winning. `target`, `cacheFrom` and `options` replace the primary values. +- **`dockerFile` and `context`.** The top-level forms are the same as `build.dockerfile` and `build.context`. Setting both forms to different paths is an error. +- **Compose.** `dockerComposeFile` takes a path or a list, and replaces the primary selection as a whole. `service` replaces the service. `runServices` replaces the sidecar list. Relative paths resolve from the declaring file, including files reached through `extends`. Paths inside the Compose YAML follow Docker Compose's own rules. +- **Required selectors.** They cannot be `null` or empty. Devsy reports an error instead of guessing. +- **`initializeCommand`.** The overlay's command replaces the primary one. It runs on the host before the build, in the workspace root. A string runs through the shell, an array runs directly, and an object runs its commands in parallel. To disable the primary command, use `""`, `[]` or `{}`. `null` is an error. +- **`runServices`.** Use `[]` to clear the primary list. +- **Features.** Precedence is primary config, then overlay, then CLI `--features`. +- **Runtime metadata.** The existing overlay behavior still applies. For example, `remoteEnv` values combine, with the overlay winning on matching keys. -Within `build`, overlay `args` merge by key, so matching overlay keys replace primary keys and other primary arguments remain. `target`, `cacheFrom`, and `options` replace their primary values when supplied. The legacy top-level `dockerFile` and `context` fields normalize to `build.dockerfile` and `build.context`; setting both forms to different paths is an error. Structural selectors that must be present cannot be `null` or empty: Devsy reports an error instead of guessing. Explicit `null` is also an error for `initializeCommand`. Use an empty `initializeCommand` (`""`, `[]`, or `{}`) to disable the primary command, and use `"runServices": []` to clear the primary list. +The feature lockfile stays next to the primary config. Structural overlays cannot attach to or replace a `containerID` config. -`dockerComposeFile` accepts a path string or a list of paths. A supplied string or list replaces the primary Compose file selection as a whole; `service` replaces the selected service, and `runServices` replaces the sidecar list. Paths in these fields are substituted before resolution. Relative paths are resolved from the file that declares them, including files inherited through `extends`, then represented relative to the primary config origin; absolute paths remain absolute. Paths inside Compose YAML, such as build contexts and bind mounts, continue to follow Docker Compose's own project-directory rules. The feature lockfile remains beside the primary devcontainer config. Structural overlays cannot attach to or replace a `containerID` config. +## Applying changes -A missing or malformed overlay is an error. Devsy resolves it before replacing an existing workspace, so a failed change leaves the current workspace available. Use `--recreate` to apply a structural change to an existing workspace: +A missing or malformed overlay is an error. Devsy reads it before replacing an existing workspace, so a failure leaves the current workspace available. To apply a structural change to an existing workspace, recreate it: ```sh devsy workspace up --recreate --devcontainer-overlay ./devcontainer/overlay.json ``` -After a successful creation, workspace cleanup uses the recorded workspace invocation. It can still delete the workspace if the overlay file is later removed or malformed. - -The overlay's `initializeCommand` replaces the primary command when present. It runs on the host with the workspace root as its working directory, before the image build. A string runs through the shell; an argument array runs directly as one command; a named-object form runs its commands in parallel. Files it creates can be used by the build when they are inside the selected build context. - -## Feature and runtime behavior - -Overlay `features` and `overrideFeatureInstallOrder` participate in image planning before feature installation. The precedence is primary config, then overlay, then CLI `--features`. Local feature paths in the overlay are relative to the overlay file. - -Runtime metadata continues to layer onto the resolved config using Devsy's existing overlay behavior. For example, overlay `remoteEnv` values combine with primary values, with overlay values taking precedence for matching keys. This support list describes the fields consumed during build planning; it does not enable arbitrary structural config replacement. +After a successful creation, workspace cleanup uses the recorded invocation, so you can still delete the workspace if the overlay file is later removed or broken. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/dotfiles-in-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/dotfiles-in-a-workspace.mdx index df13d62744..aa30646a8f 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/dotfiles-in-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/dotfiles-in-a-workspace.mdx @@ -3,60 +3,32 @@ title: Dotfiles in a Workspace sidebar_label: Dotfiles in a Workspace --- -## Personalizing a Workspace +Devsy can clone your dotfiles repository into a workspace and install it, so your shell and tool settings are there every time. -You can personalize your workspace environment by using a `dotfiles` repository. +Pass the repository with `--dotfiles`: -Dotfiles are plain text configuration files on Unix like systems (e.g. MacOS, Linux, BSD). -Dotfiles store settings of almost every application, service and tool running on your system. -It is common practice to track dotfiles with a version control system such as Git -to keep track of changes and synchronize dotfiles across various hosts. - -You can use the `--dotfiles` flag when creating a workspace, so that Devsy will -automatically clone and install your dotfiles in the workspace. - -If you only specify the dotfiles repo, Devsy will clone your selected dotfiles -repository into the workspace, and will look into one of these locations to find -a script to setup the environment. - -- install.sh -- install -- bootstrap.sh -- bootstrap -- script/bootstrap -- setup.sh -- setup -- setup/setup - -If none of the previous locations are found, Devsy will just link every hidden file (files starting with `.`) -in the `$HOME` directory of the container. - -It is possible to specify **custom install script locations** for your special setup. -If a custom install script is specified, Devsy will directly run that one instead. +```sh +devsy workspace up https://github.com/example/repo --dotfiles https://github.com/my-user/my-dotfiles-repo +``` -### Devsy CLI +Devsy then looks in the repository for one of these install scripts and runs the first it finds: -Run the following command to start a workspace with a dotfiles repo: +- `install.sh`, `install` +- `bootstrap.sh`, `bootstrap`, `script/bootstrap` +- `setup.sh`, `setup`, `setup/setup` -``` -devsy workspace up https://github.com/example/repo --dotfiles https://github.com/my-user/my-dotfiles-repo -``` +If there is none, Devsy links every hidden file (names starting with `.`) into the container's `$HOME`. -Specifying a custom install script: +To run a different script, name it: -``` +```sh devsy workspace up https://github.com/example/repo --dotfiles https://github.com/my-user/my-dotfiles-repo --dotfiles-script custom/location/install.sh ``` -#### For all Workspaces +## For all workspaces -You can setup these options on a **context wide scope** so that you won't have to specify -`dotfiles` and `dotfiles-script` for each single workspace: +Set the options on the context so every new workspace uses them: -Example with a real repository: - -``` -devsy context set -o DOTFILES_URL=https://github.com/89luca89/dotfiles -o DOTFILES_SCRIPT=bin/.local/bin/dotfiles +```sh +devsy context set -o DOTFILES_URL=https://github.com/my-user/my-dotfiles-repo -o DOTFILES_SCRIPT=bin/install.sh ``` - -All new Workspaces will be created with that dotfile repository and install script. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/inactivity-timeout.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/inactivity-timeout.mdx index 3eed1756eb..1956282a58 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/inactivity-timeout.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/inactivity-timeout.mdx @@ -3,37 +3,20 @@ title: Auto-Inactivity Timeout sidebar_label: Auto-Inactivity Timeout --- -By default, most providers are able to automatically shutdown unused workspaces to save costs. For example, for cloud providers such as AWS, Azure and Google Cloud, Devsy will automatically stop the machine to save costs when workspaces are not used. +Providers can stop workspaces that nobody is using, which saves cost. A machine stopped this way keeps its data, and Devsy restarts it when you start the workspace again. -Machines stopped this way preserve the data and state, so when a workspace [is started again](./connect-to-a-workspace.mdx), Devsy will simply restart the machine and the workspace. +## Configure the timeout - -All official Devsy providers offer this pre-configured to 5-10 minutes. Check the provider options to see how to change the timeout. - - -## Configuring the timeout - -Changing the default setting for inactivity timeout can be done by [configuring the provider options](../managing-providers/manage-providers.mdx#set-provider-options). Typically there is an option called `INACTIVITY_TIMEOUT` that controls this behaviour. - - -More info about the provider's auto-shutdown can be found in the [agent's development guide](../developing-providers/agent.mdx#machine-providers) -That will explain how this is done and what can be configured. - - -## How does it work? +Each provider has an `INACTIVITY_TIMEOUT` option, for example `30m`. See [Set provider options](../managing-providers/manage-providers.mdx#set-provider-options). The provider's options show its default. -### Non-Machine Providers +## How it works -For non-machine providers, Devsy can automatically kill the container it's running in by terminating the process with pid 1. This is useful for providers such as docker, podman, kubernetes or ssh, where you don't want the container to be running if it's not needed. If configured on the provider, Devsy will start a process within the container to keep track of activity and then kill itself when the user hasn't connected for the given duration. This will not erase any state within the container and instead only stop it. Then when the user wants to start working with the workspace again, Devsy will restart the container. +**Non-machine providers** such as Docker, Podman, Kubernetes, and Microsandbox run a process in the container that tracks activity. When nobody has connected for the timeout, it ends the container's main process. The container stops, its state is kept, and Devsy restarts it later. - -The Apple provider is the exception: its `INACTIVITY_TIMEOUT` option description states that it deletes the container after the idle period, rather than just stopping it like Docker, Podman and Microsandbox. As with any deleted (non-machine) container, only data on mounted volumes survives; anything in the writable layer is lost. + +The Apple provider deletes the container instead of stopping it. Only data on mounted volumes survives. -### Machine Providers +**Machine providers** run a Devsy daemon on the VM. When there is no activity for the timeout, the daemon shuts the machine down or deletes it, whichever costs less for that cloud. Devsy restarts or recreates it when you resume. -For machine providers, killing just the container within the remote machine is typically not enough as VMs still generate costs even if they are unused. Instead, Devsy will install itself as a Daemon into the remote VM and track the activity from there. If there wasn't activity for a given amount of time, Devsy will automatically shutdown the machine or even delete it, based on whichever is more cost-effective for the given cloud provider. Then when the developer wants to resume development, Devsy restarts or recreates the virtual machine. - - -See [agent's development guide](../developing-providers/agent.mdx#machine-providers) to learn more about how inactivity-timeout works on the provider side. - +See the [agent guide](../developing-providers/agent.mdx#machine-providers) for how providers implement this, and [Machine diagnostics](../managing-machines/machine-diagnostics.mdx) for debugging. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/mcp-server.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/mcp-server.mdx index 235f2e0ae8..18933a4a0c 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/mcp-server.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/mcp-server.mdx @@ -3,43 +3,13 @@ title: Agent Control via MCP sidebar_label: Agent Control (MCP) --- -# Agent Control via MCP - -`devsy mcp serve` runs a [Model Context Protocol](https://modelcontextprotocol.io) server over stdio. MCP-compatible AI clients can connect to it and drive Devsy - listing, creating, and executing inside workspaces - without shelling out to the CLI themselves. +`devsy mcp serve` runs a [Model Context Protocol](https://modelcontextprotocol.io) server over stdio. AI clients that support MCP can use it to list, create, and run commands in workspaces. ```sh devsy mcp serve ``` -The server reads JSON-RPC frames from stdin and writes them to stdout. Configure your MCP client to launch the command; it will discover the registered tools at startup. - -## Tools exposed - -The server registers 11 tools across workspace and provider domains: - -| Tool | Purpose | -|---|---| -| `workspace_list` | List all workspaces with provider, IDE, and source. | -| `workspace_status` | Get saved workspace configuration (not live running state). | -| `workspace_create` | Create and start a new workspace. | -| `workspace_start` | Start (or resume) an existing workspace. | -| `workspace_stop` | Stop a running workspace. | -| `workspace_delete` | Delete a workspace by name. Accepts `force=true`. | -| `workspace_exec` | Run a one-shot command inside a running workspace. | -| `provider_list` | List configured providers. | -| `provider_add` | Add a provider from a registry name, GitHub URL, or local path. | -| `provider_delete` | Remove a configured provider. | -| `provider_use` | Set the default provider for new workspaces. | - -`workspace_exec` is bounded by three server flags: - -- `--exec-timeout-default` (default `5m`) - default per-call timeout. -- `--exec-timeout-max` (default `30m`) - caller-supplied timeouts are clamped to this. -- `--exec-output-cap` (default `100 KiB`) - per-stream byte cap; excess is replaced with a truncation marker. - -## Example client config - -The exact format depends on your MCP client, but every client needs the command to launch and any arguments. A generic JSON shape looks like: +Configure your MCP client to launch that command. The exact config format depends on the client. A typical shape: ```json { @@ -52,59 +22,36 @@ The exact format depends on your MCP client, but every client needs the command } ``` -Check your client's documentation for where this config lives (e.g. `claude_desktop_config.json` for Claude Desktop). Refer to the [MCP specification](https://modelcontextprotocol.io/specification) for transport and tool semantics. +## Tools -## Install the Devsy Agent Skill +| Tool | Purpose | +|---|---| +| `workspace_list` | List workspaces with provider, IDE, and source. | +| `workspace_status` | Get the saved workspace configuration. It does not report whether the workspace is running. | +| `workspace_create` | Create and start a workspace. | +| `workspace_start` | Start an existing workspace. | +| `workspace_stop` | Stop a running workspace. | +| `workspace_delete` | Delete a workspace. Accepts `force=true`. | +| `workspace_exec` | Run a one-shot command in a running workspace. | +| `provider_list` | List configured providers. | +| `provider_add` | Add a provider from a registry name, GitHub URL, or local path. | +| `provider_delete` | Remove a provider. | +| `provider_use` | Set the default provider. | -MCP provides the tools to control Devsy. The first-party Agent Skill teaches -an agent how to select workspaces and providers, execute commands, recover from -timeouts, and use CLI diagnostics when needed. It is for using Devsy, rather -than contributing to the Devsy source repository. +To check whether a workspace is running, use `devsy workspace status --result-format json`. -After installing Devsy, configure your agent's MCP client to launch -`devsy mcp serve`, then install the skill: +`workspace_exec` is limited by flags on `devsy mcp serve`: `--exec-timeout-default` (5m), `--exec-timeout-max` (30m), and `--exec-output-cap` (100 KiB per stream). `--mcp-max-concurrent-ops` (8) limits concurrent exec, create, and start calls. -```sh -npx skills add devsy-org/devsy --skill devsy -``` +## Agent skill -For use across projects, add `-g`. To target a particular agent, use `--agent`: +Devsy also publishes an agent skill that teaches an agent how to pick workspaces and providers, run commands, and recover from timeouts. It is separate from the MCP server: installing it does not install Devsy or configure MCP. It needs Node.js for `npx`. ```sh -npx skills add devsy-org/devsy --skill devsy -g -npx skills add devsy-org/devsy --skill devsy --agent codex -npx skills add devsy-org/devsy --skill devsy --agent claude-code -``` - -The Agent Skill and MCP configuration are separate. Installing the skill does -not install Devsy, configure MCP, or set up a provider. The installer requires -Node.js/`npx`; Devsy itself does not depend on it. See the -[skills installer](https://github.com/vercel-labs/skills) for supported clients -and updates. Follow your agent's instructions for reloading newly installed -skills or MCP configuration. - -### Hand this to your agent - -Copy this prompt into the agent you want to use with Devsy: - -```text -Set up the published first-party Devsy skill for this agent so you can operate -Devsy workspaces for me. Check whether Devsy is installed and supports -`devsy mcp serve`. Install the devsy skill from devsy-org/devsy for this agent; -use a project installation unless I ask for global installation. Follow this -agent's current MCP setup instructions to configure Devsy, preserving existing -MCP entries. If installation or configuration cannot be completed, tell me -which prerequisite is missing and the exact next step. Verify the integration -by listing my Devsy workspaces without creating or changing any. Report what -was installed/configured and whether the connection worked. +npx skills add devsy-org/devsy --skill devsy ``` -After setup, try: "Create a Devsy workspace for this repository and run its -tests," or "Stop my example workspace." The skill prefers MCP tools and uses -the CLI for operations the connected server does not expose. For live running -state, the current MCP `workspace_status` result is only saved configuration; -`devsy workspace status --result-format json` probes live state. +Add `-g` to install it for all projects, or `--agent` to target one agent. ## Security -The MCP server has the same authority as your local Devsy CLI. A connected client can create, modify, and delete workspaces, run arbitrary commands inside them, and add or remove providers. Only enable `devsy mcp serve` for clients you trust. +The MCP server has the same authority as your local Devsy CLI. A connected client can create and delete workspaces, run any command in them, and add or remove providers. Only use it with clients you trust. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/prebuild-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/prebuild-a-workspace.mdx index 99fb13af27..86ccbd772b 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/prebuild-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/prebuild-a-workspace.mdx @@ -3,48 +3,31 @@ title: Prebuild a Workspace sidebar_label: Prebuild a Workspace --- -## Prebuild a Workspace +A prebuild is an image built ahead of time from `devcontainer.json`, its features, and any Dockerfile. When a prebuild exists, Devsy starts from it instead of building, which saves time on complex environments. -Prebuilding a workspace means building a ready-to-use docker image out of the `devcontainer.json`, its referenced features and optionally a linked `Dockerfile`. -Usually when creating a new workspace, Devsy will first build a docker image based on the configuration and then later use this image to create the development environment. -With prebuilds, this step can be omitted and Devsy can directly use the docker image to start the development environment. This can save start up time, especially for more complex development environments. +## How it works -### How does it work? +Devsy hashes the devcontainer configuration and uses `devsy-` plus the hash as the image tag. When you point Devsy at an image repository, it looks for that tag and uses the image if found. -Based on the `devcontainer.json` configuration, Devsy will generate a hash in the form of `devsy-HASH` and use this as a tag for the created docker image. -You can then reference docker image repositories, where Devsy will search this tag and if found uses it instead of building the image itself. +Build and push a prebuild: -To prebuild a workspace, you can run the following command: -``` -# Prebuild the docker image for github.com/my-org/my-repo and save it in image registry ghcr.io/my-org/my-repo +```sh devsy workspace build github.com/my-org/my-repo --repository ghcr.io/my-org/my-repo ``` - -Devsy will only build the workspace if there isn't an existing prebuild found in the specified docker image repository - - -Devsy will use the current provider for doing this, which means you can also use remote providers to prebuild an image. You can even have a separate provider just for prebuilding images. - -## Using Prebuilds - -Using prebuilds means you specify a docker image repository, where Devsy will search for an image with a specific hash generated from the devcontainer configuration. You can either specify this prebuild repository via a flag during workspace creation or directly in the `devcontainer.json`. +Devsy skips the build if the repository already has an image with the matching tag. It uses your current provider, so you can prebuild on a remote provider or a dedicated one. - -If a prebuild cannot be found in the given repository or credentials are missing locally, Devsy will just skip the repository. - +## Use a prebuild -### Reference Prebuild Repository as Flag +Pass the repository when you create a workspace: -When creating a new workspace, you can define the prebuild repository via the `--prebuild-repo` flag: -``` +```sh devsy workspace up github.com/my-org/my-repo --prebuild-repo ghcr.io/my-org/my-repo ``` -### Reference Prebuild Repository in devcontainer.json +Or set it in `devcontainer.json`, which suits builds run from CI: -It's also possible to include the prebuild repository directly in the `devcontainer.json`, which makes it easy to automate prebuilding through a CI/CD pipeline on changes. You can specify the prebuild repository via: -``` +```json { "name": "my-project", "customizations": { @@ -54,3 +37,5 @@ It's also possible to include the prebuild repository directly in the `devcontai } } ``` + +If no matching image is found, or you lack credentials for the repository, Devsy skips it and builds as usual. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/secrets.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/secrets.mdx index 0a833ae0f7..20b52f632e 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/secrets.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/secrets.mdx @@ -3,427 +3,157 @@ title: Secrets in a Workspace sidebar_label: Secrets --- -Devsy can inject sensitive values into workspaces without placing plaintext -credentials in `devcontainer.json`, command-line arguments, or ordinary dotenv -files. +Devsy can inject sensitive values into a workspace without putting plaintext in `devcontainer.json`, command-line arguments or dotenv files. Values come from two places: -Secrets can come from two places: +- **Devsy-managed secrets**, stored in your OS keyring or in an encrypted local file. +- **External sources**, such as a SOPS-encrypted file. Devsy reads them when needed and never copies them into its own store. -- **Devsy-managed secrets** - values owned by Devsy and stored in the operating - system keyring or Devsy's encrypted local file. -- **External secret sources** - values owned by another system, such as a - SOPS-encrypted file. Devsy resolves these values when they are needed and does - not import them into the local Devsy secret store. +Both use the same delivery paths: environment variables for lifecycle commands, in-memory files under `/run/secrets`, and build secrets. -Both use the same protected workspace delivery paths: lifecycle environment -variables, in-memory files under `/run/secrets`, and supported build-secret -mechanisms. +## Devsy-managed secrets -## Devsy-Managed Secrets - -With the default `auto` storage backend, Devsy stores sensitive values in your -operating system's keyring when one is available: - -- **macOS** - Keychain -- **Windows** - Credential Manager -- **Linux** - Secret Service (libsecret / GNOME Keyring / KWallet) - -When no keyring is available, or when the `file` backend is selected, Devsy -stores values in an age-encrypted `secrets.enc` file in the Devsy config -directory. Only non-sensitive metadata such as names and timestamps is written -in plaintext. Devsy-managed secrets are scoped to the active -[context](../managing-providers/what-are-providers). - -### Creating a Secret +Secrets are scoped to the active context. With the default `auto` backend, Devsy uses the OS keyring when there is one (Keychain, Credential Manager, or Secret Service on Linux). Otherwise it uses an age-encrypted `secrets.enc` file in the Devsy config directory. Only metadata such as names and timestamps is stored in plaintext. ```shell -# Interactive input; the value is not echoed. -devsy secret set DB_PASSWORD - -# Standard input is recommended for scripts. -printf '%s' "$MY_VALUE" | devsy secret set DB_PASSWORD --stdin - -# Or read a value from a file. +devsy secret set DB_PASSWORD # hidden prompt +printf '%s' "$MY_VALUE" | devsy secret set DB_PASSWORD --stdin # for scripts devsy secret set TLS_KEY --from-file ./tls.key -``` - -### Listing, Reading, and Deleting - -```shell -devsy secret list +devsy secret list # never prints values devsy secret get DB_PASSWORD devsy secret delete DB_PASSWORD ``` -`devsy secret list` never prints values and can show secret metadata while a -backend is locked. Its availability status is separate from the backend that -owns the value. Operations that need plaintext, including `get` and workspace -startup, still fail when a required value cannot be read. - -### Managing Variables in Desktop +In Desktop, **Workspace Variables** manages secrets and environment variables. Secret values are never shown. -Open **Workspace Variables** to manage configuration in two tabs: -**Secrets** and **Environment Variables**. Each table shows the name, context, -and workspace injection setting. Secret rows also show their storage backend -and availability. Secret values are never displayed. +## External sources (SOPS) -Use **Add secret** or **Add variable** to create an entry. To change an existing -entry, open its details and choose **Replace secret value** for a secret or edit -the environment value. Names are scoped to a context, so the same name in another -context is a separate entry. Desktop checks for existing names when adding; -the CLI `set` commands continue to create or update values. - -Locked secrets remain visible, and you can change their **Inject into -workspaces** setting without unlocking. This changes the context attachment, -not the stored value. Reading, replacing, or deleting file-backed values can -still require unlocking. A locked file store does not prevent access to -available keyring-backed secrets or managed environment variables. - -Environment values are masked by default in Desktop and can be revealed for -an individual row. Masking only hides the display: environment variables are -stored in plaintext and are intended for non-sensitive configuration. - -## External Secret Sources - -An external secret source lets Devsy resolve a value at workspace startup -without making Devsy a second source of truth for that value. - -### SOPS - -Devsy supports [SOPS](https://github.com/getsops/sops)-encrypted YAML, JSON, and -dotenv files. Devsy uses the SOPS Go implementation; installing a -`sops` executable is not required. - -SOPS source documents use flat top-level key/value pairs in the initial -implementation: +Devsy reads [SOPS](https://github.com/getsops/sops)-encrypted YAML, JSON and dotenv files. It does not need the `sops` executable. The files must be flat top-level key/value pairs: ```yaml DATABASE_PASSWORD: ENC[...] API_TOKEN: ENC[...] ``` -### Registering a Local SOPS Source - -If the encrypted file is already available on the machine running Devsy, add a -named source: +Register a local file as a named source. Devsy checks that it can decrypt the file first, and stores only the name, type, path and format override: ```shell devsy secret source add sops project ./secrets.enc.yaml -``` - -Devsy validates that the file can be decrypted before saving the source. The -configuration stores the source name, type, file path, and (when set via -`--format`) the document format override only. Decrypted values are not -copied into the keyring or Devsy's `secrets.enc` file. - -List or remove locally registered sources with: - -```shell devsy secret source list devsy secret source remove project ``` -A source cannot be removed while context-level secret bindings still reference -it. +A source cannot be removed while a context secret attachment still references it. -### Repository-Owned SOPS Sources - -A repository can declare SOPS sources in either the root-level `.devcontainer.json` or `.devcontainer/devcontainer.json` layout under `customizations.devsy.secretSources`. - -```text -project/ -├── .devcontainer/ -│ └── devcontainer.json -└── secrets.enc.yaml -``` +### Sources declared by a repository -Example `devcontainer.json`: +A repository can declare sources in `customizations.devsy` in its `devcontainer.json`: ```json { - "name": "My Project", "image": "mcr.microsoft.com/devcontainers/base:ubuntu", "customizations": { "devsy": { "secretSources": [ - { - "name": "project", - "type": "sops", - "path": "./secrets.enc.yaml" - } + { "name": "project", "type": "sops", "path": "./secrets.enc.yaml" } ], - "secrets": [ - "sops:project/DATABASE_PASSWORD" - ] + "secrets": ["sops:project/DATABASE_PASSWORD"] } } } ``` -Repository source paths are resolved relative to the repository root. Devsy -rejects paths, including symlink targets, that escape the repository root. - -Repository-owned sources work with a local checkout: - -```shell -devsy workspace up . -``` - -and with a remote Git source: - -```shell -devsy workspace up https://github.com/acme/project -``` - -For a remote source Devsy first acquires repository data to read the requested Git -revision, then reads `customizations.devsy` from the effective Dev Container -configuration and the referenced encrypted SOPS files from that same revision. - -### Bootstrap Authentication for Private Repositories - -Credentials needed to acquire a private repository must be available **before** -Devsy can inspect repository-owned SOPS files. - -For example, this is valid: - -```text -local Devsy secret / Git credential / SSH agent - │ - ▼ - authenticate repository clone - │ - ▼ - repository SOPS runtime secrets -``` - -A repository-owned SOPS secret cannot authenticate the clone of the same -repository that contains it. -`--git-token` may reference a Devsy-managed secret or another external source -that is already locally available before repository acquisition. +Paths are relative to the repository root. Paths that escape it, including through symlinks, are rejected. This works for a local checkout (`devsy workspace up .`) and a remote repository, where Devsy reads the files from the same Git revision. -## Referencing Secrets +Credentials needed to clone a private repository must exist before Devsy can read the repository's SOPS files. A repository's own secret cannot authenticate the clone of that repository. `--git-token` can reference a managed secret or another source that is already available locally. -An unqualified name continues to mean a Devsy-managed local secret: +### Credentials for SOPS -```text -DB_PASSWORD -``` - -An external source uses a source-qualified reference: +Devsy leaves key discovery to SOPS. For age, set `SOPS_AGE_KEY` or `SOPS_AGE_KEY_FILE`, or use the standard age key location. For AWS KMS, GCP KMS, Azure Key Vault and PGP, use the same configuration you would use with SOPS. -```text -sops:project/DB_PASSWORD -``` +## Referencing secrets -Devsy does not search other sources if a reference cannot be resolved. Explicit -source selection prevents one source from silently shadowing another. +An unqualified name is a Devsy-managed secret: `DB_PASSWORD`. An external secret is source-qualified: `sops:project/DB_PASSWORD`. Devsy never searches other sources when a reference does not resolve. If any requested value cannot be resolved, `workspace up` fails. -### Lifecycle Environment Variables +### Environment variables -`--secret` is repeatable. By default, Devsy exposes the requested value as an -environment variable to lifecycle commands: +`--secret` is repeatable and exposes the value to lifecycle commands during that `workspace up`. It does not appear in later terminal sessions. ```shell devsy workspace up . --secret DB_PASSWORD -devsy workspace up . --secret sops:project/DATABASE_PASSWORD +devsy workspace up . --secret sops:project/DATABASE_PASSWORD,target=DB_PASSWORD ``` -Use `target=` to change the environment-variable name: - -```shell -devsy workspace up . \ - --secret sops:project/DATABASE_PASSWORD,target=DB_PASSWORD -``` +`target=` renames the variable. Repository `secrets` bindings have the same scope. -An explicit `--secret` value is available to lifecycle commands during that -`workspace up`. It does not become an environment variable in later terminal -sessions. Repository `customizations.devsy.secrets` bindings have the same -lifecycle-only scope. +### Files -### Mounted Secret Files - -Use `type=mount` to write the secret to the existing in-memory secret mount: +`type=mount` writes the value to an in-memory file under `/run/secrets`: ```shell -devsy workspace up . \ - --secret sops:project/TLS_KEY,type=mount,target=tls.key +devsy workspace up . --secret sops:project/TLS_KEY,type=mount,target=tls.key ``` -The value is available at: - -```text -/run/secrets/tls.key -``` - -Providers that cannot offer an in-memory secret mount reject `type=mount` with an error. - -### Build Secrets +The file is `/run/secrets/tls.key`. Providers without an in-memory mount reject this with an error. -Source-qualified references can also be used with Devsy's existing build-secret -path: +### Build secrets ```shell devsy workspace up . --build-secret sops:project/NPM_TOKEN ``` -The build secret ID is the secret key (`NPM_TOKEN`), not the complete -source-qualified reference. Builds continue to consume it through the existing -BuildKit secret mechanism, for example: +The build secret ID is the key (`NPM_TOKEN`), not the full reference. Use it in a Dockerfile with `RUN --mount=type=secret,id=NPM_TOKEN ...`. -```dockerfile -RUN --mount=type=secret,id=NPM_TOKEN ... -``` - -### Attaching a Secret to a Context +### Attach a secret to a context -Attach a locally available secret reference to the active context so it is -injected during workspace setup and into new Devsy-managed terminal/SSH -sessions: +An attached secret is injected during workspace setup and into every new Devsy-managed SSH or terminal session, including `devsy workspace ssh` and the Desktop terminal: ```shell devsy secret attach DB_PASSWORD devsy secret attach sops:project/API_TOKEN -``` - -Detach it with: - -```shell devsy secret detach DB_PASSWORD -devsy secret detach sops:project/API_TOKEN -``` - -Attachments are context-scoped and contain only the secret reference, never -the value. The Desktop Workspace Variables **Secrets** tab shows and changes -the same attachment state. Devsy resolves an attached secret on `workspace up`, makes it available -to lifecycle commands, and supplies it to each new Devsy-managed SSH session -and its child processes. This includes `devsy workspace ssh` and the Desktop -workspace terminal. It does not set a global container environment variable -or change processes and sessions that are already running. After detaching, -run `workspace up` or recreate the workspace for future sessions to lose the -value. - -An attached secret is a context default. An explicit session environment such -as `workspace ssh --set-env NAME=value` takes precedence over the attached -value for that session. When names collide, new sessions use this order: - -```text -explicit session environment > attached secret > base container/user environment ``` -Devsy recreates an existing managed workspace when it needs to add the -terminal-secret runtime mount. Setup verifies that `/run/devsy/secrets-env` is -itself a `tmpfs` mount before writing any attached terminal secret. If the -provider cannot create that mount, setup fails instead of writing the value to -the container's writable layer. +Only the reference is stored. Already-running sessions do not change. After detaching, run `workspace up` or recreate the workspace so new sessions lose the value. If names collide, a session uses: explicit session environment (`workspace ssh --set-env`), then attached secret, then the container's own environment. -Devsy stores only the reference for an external secret. Repository-owned -`customizations.devsy` can declare project-specific automatic -bindings with its `secrets` list. If any requested or attached value cannot be -resolved, `workspace up` fails rather than silently starting without it. +Terminal secrets are copied to `/run/devsy/secrets-env`, an owner-only `tmpfs` mount. If the provider cannot create that mount, setup fails instead of writing to the container's disk. Devsy may recreate an existing managed workspace to add it. -### Secret Delivery Scope +### Where each kind is available -| Source | Lifecycle environment | New Devsy SSH/terminal sessions | File mount | Image build | +| Source | Lifecycle environment | New SSH or terminal sessions | File mount | Image build | | --- | --- | --- | --- | --- | -| Context-attached secret | Yes | Yes | No | No | -| `workspace up --secret NAME` | Yes | No | No | No | -| `workspace up --secret NAME,type=mount` | No (file only) | No | `/run/secrets/` | No | -| `workspace up --secrets-file ...` | Yes | No | No | No | -| Project `customizations.devsy.secrets` binding | Yes | No | No | No | -| `workspace up --build-secret NAME` | No | No | No | BuildKit only | - -Environment-injected secrets are inherited by child processes started in the -lifecycle hook or terminal session. Use `type=mount` when file-based access is -appropriate and a narrower process-environment scope is preferred. Build -secrets are available only to build steps that request them. - -## SOPS Credential Discovery +| Attached secret | Yes | Yes | No | No | +| `--secret NAME` | Yes | No | No | No | +| `--secret NAME,type=mount` | No | No | `/run/secrets/` | No | +| `--secrets-file` | Yes | No | No | No | +| Repository `secrets` binding | Yes | No | No | No | +| `--build-secret NAME` | No | No | No | BuildKit only | -Devsy delegates key and KMS credential discovery to SOPS instead of creating a -parallel credential system. +Environment variables are inherited by child processes. Use `type=mount` for a narrower scope. -For age-encrypted files, normal SOPS mechanisms apply, including -`SOPS_AGE_KEY`, `SOPS_AGE_KEY_FILE`, and the standard SOPS age-key location. -For example: +## How secrets are protected -```shell -export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt" -devsy workspace up . -``` - -For AWS KMS, GCP KMS, Azure Key Vault, PGP, and other key services supported by -SOPS, use the same credentials and key configuration you would use with -SOPS itself. - -## How Secrets Are Protected - -Devsy workspaces protect sensitive values by: - -- Decrypting SOPS sources in memory at workspace startup without persisting plaintext to disk -- Injecting secrets directly as environment variables or memory-backed files under `/run/secrets` -- Redacting known secret values from logs and terminal outputs -- Excluding secret values from client-server transport and workspace metadata +- SOPS sources are decrypted in memory and never written to disk. +- Secrets are delivered as environment variables or memory-backed files. +- Known secret values are redacted from logs and terminal output. +- Values are kept out of client-server transport and workspace metadata. -Context attachments store secret references only. Values remain in their -configured secret backend and are transferred during workspace setup through -Devsy's protected secret-delivery channel. For new Devsy-managed terminal -sessions, selected values are copied to an owner-only, memory-backed runtime -location and read only when the SSH server starts the session. This location -is `/run/devsy/secrets-env`, must be an exact `tmpfs` mount, is not the -container's global environment, and is excluded from workspace metadata and -snapshots. +## Storage backends -### Choosing a Devsy Storage Backend +Metadata is in `secrets.yaml`. Each secret records its backend when created, and it does not move if you change the preference later. Backends: -Devsy stores managed secrets and managed environment variables separately. -Secret metadata lives in `secrets.yaml`; file-backed secret values share the -encrypted `secrets.enc` file. Managed environment values are plaintext in the -separate `env.yaml` file. Environment commands read and write that file -without opening or unlocking any secret backend, so a locked secret store does -not prevent `devsy env` operations. Environment values are not protected -secrets; use `devsy secret` for sensitive values. +- `keyring`: the OS keyring. +- `file`: the age-encrypted `secrets.enc`. +- `auto`: use `keyring` when available, otherwise `file`. This is only a preference for new secrets. -Devsy-managed secrets use one of two storage backends: - -- `keyring` - the OS keyring (Keychain / Credential Manager / libsecret). -- `file` - an [age](https://age-encryption.org)-encrypted `secrets.enc` stored - alongside the Devsy config. - -Choose a backend preference for newly created secrets: - -- `auto` - prefer the keyring when available and otherwise use `file`. -- `keyring` - store new secrets in the OS keyring. -- `file` - store new secrets in the encrypted file store. - -Set a persistent preference per context with: +Set the preference for a context, or for one command with `DEVSY_SECRETS_BACKEND`: ```shell devsy context set -o SECRETS_BACKEND=file ``` -Or override it for one command with `DEVSY_SECRETS_BACKEND`. - -These preferences select storage only when a new Devsy-managed secret is -created. After creation, its concrete backend is recorded in `secrets.yaml` and -does not change when the preference changes. `auto` is never recorded as the -backend for an existing secret. +### Passphrase for the file store -The `file` backend uses one protection mode for the complete `secrets.enc` -store: an automatically managed key or a passphrase. This protection mode is -independent of the backend preference. Changing `SECRETS_BACKEND` affects -where future secrets are stored; it does not change how existing file-backed -secrets are protected. - -When a new file store is initialized, an explicit passphrase or -`DEVSY_SECRETS_PASSPHRASE` can select passphrase protection. The -passphrase-file and remembered-keychain sources unlock a store that is already -passphrase protected; they do not choose the protection mode for a new store. -To set the mode deliberately before storing secrets, run -`devsy secret protection set-passphrase`. - -### Protecting the File Store with a Passphrase - -Configure passphrase protection with the `devsy secret protection` commands: +The file store is protected either by an automatically managed key or by a passphrase. The mode applies to the whole file, across all contexts, and is independent of the backend preference. ```shell devsy secret protection status @@ -432,95 +162,38 @@ devsy secret protection change-passphrase devsy secret protection remove-passphrase ``` -`status` reports the file store's protection mode and availability, including -whether a remembered credential is available. - -In Desktop, open **Manage security** from the **Secrets** tab or the compact -**Secret Security** section in Settings. The security sheet shows the file -store's protection and availability and whether a credential is remembered on -this device. Protection applies to file-backed secrets across all contexts. - -Changing file-store protection or its remembered credential requires -confirmation in a native application dialog. Canceling -the dialog leaves protection and the remembered credential unchanged. -Choosing to remember a passphrase while unlocking also requires native -confirmation and an active unlock request. - -Use **Remember on this device** to save a verified passphrase in the operating -system credential store. **Forget this device** removes that saved credential; -it does not change file-store protection or delete secrets. A passphrase -already cached by the running Desktop application may still provide access. - -The advanced **Clear session passphrase** action removes the Desktop's -in-memory passphrase. Other available credentials may still unlock the store. An approved protection change already running -may finish, but it will not restore -the cleared session credential. Remembered OS-keychain credentials remain -until you choose **Forget this device**. - -While an unlock submission is running, another credential submission for that -request is rejected. You can still cancel unlocking. If an approved Remember -action then succeeds, Desktop reports that the credential was saved even though -unlocking was canceled. The main process retains this notice across a page -reload until Desktop displays and acknowledges it. Use **Forget this device** -to remove the credential. - -Passphrase protection applies to all values in the file backend. It is not a -secret storage backend or a per-secret setting. To supply the passphrase, Devsy -checks sources in this order: explicit input from the invoking UI or process, -`DEVSY_SECRETS_PASSPHRASE`, `DEVSY_SECRETS_PASSPHRASE_FILE`, an opt-in -remembered credential in the operating-system keyring, then an interactive -prompt when the command supports prompting. A supplied credential that fails -to unlock the store is an error; Devsy does not fall through to a lower -priority source. - -For automation, set `DEVSY_SECRETS_PASSPHRASE_FILE` to a file containing the -passphrase. Devsy accepts files up to 64 KiB, strips at most one trailing -newline, and rejects an empty passphrase. On Unix, the file must have -restrictive permissions (readable only by its owner, such as mode `0600`). -Configure projected container or Kubernetes secret files with a similarly -restrictive mode. The file path is host-specific and is not saved in context -configuration. - -Remembering a passphrase is opt-in and stores it in the operating-system -credential store shared by the CLI and Desktop: +Devsy looks for the passphrase in this order, and a credential that fails is an error, with no fallback: + +1. Explicit input from the UI or process. +2. `DEVSY_SECRETS_PASSPHRASE`. +3. `DEVSY_SECRETS_PASSPHRASE_FILE`. +4. A remembered credential in the OS keyring. +5. An interactive prompt, where supported. + +For automation, first run `devsy secret protection set-passphrase`, then point `DEVSY_SECRETS_PASSPHRASE_FILE` at a file of up to 64 KiB. The file only unlocks an existing passphrase-protected store. It does not choose the protection mode for a new store. Devsy strips one trailing newline, rejects an empty passphrase, and on Unix requires owner-only permissions such as `0600`. + +Remembering the passphrase is optional and shared by the CLI and Desktop: ```shell devsy secret protection remember devsy secret protection forget ``` -`remember` verifies the current passphrase before saving it. `forget` removes -only the remembered credential; it does not change encryption or delete -secrets. +`forget` removes only the saved credential. It does not change encryption or delete secrets. In Desktop, use **Manage security** on the **Secrets** tab. Changing protection needs confirmation in a native dialog. + +### Recovery -In Desktop, **Recovery options** explains how to restore access and provides -the reset command to copy. A remembered device credential may still unlock -the store if you have forgotten the passphrase. Without a valid credential, -the encrypted file contents cannot be decrypted. Resetting removes every -file-backed secret entry across all contexts; use it only after reviewing the -recovery options. Reset the complete file-backed store from the CLI with -explicit confirmation: +Without the passphrase or a valid remembered credential, the file contents cannot be decrypted. As a last resort, reset the whole file store: ```shell devsy secret protection reset-file-store ``` -The reset lists all file-backed secret names across contexts. Confirm -interactively by typing `RESET`, or use `--yes` for explicit non-interactive -confirmation. If `secrets.enc` exists, Devsy moves it to a quarantine filename -for possible manual recovery. Reset removes file-backed metadata and removes -the remembered credential when the operating-system keychain is accessible. -If the keychain is unavailable during reset, restore access and run -`devsy secret protection forget` to remove that credential. Reset leaves -keyring-backed secrets and the independent plaintext `env.yaml` environment -store untouched. Recreate any lost file-backed secrets afterward. External -sources such as SOPS continue to use their own credentials and are not -affected by this local file-store setting. +This lists every file-backed secret across all contexts and asks you to type `RESET`, or pass `--yes`. It moves `secrets.enc` to a quarantine file, removes the file-store metadata, and removes the remembered credential when the keychain is reachable. It leaves keyring secrets and `env.yaml` alone. You must recreate the lost secrets. -## Managed Environment Variables +## Managed environment variables -For non-sensitive configuration, `devsy env` stores managed environment -variables in plaintext in the separate `env.yaml` file: +For non-sensitive settings, `devsy env` stores plaintext values in `env.yaml`, separate from secrets. It works even when the secret store is locked. Never put a sensitive value here. ```shell devsy env set LOG_LEVEL=debug @@ -530,51 +203,23 @@ devsy env get LOG_LEVEL devsy env delete LOG_LEVEL ``` -Inject them with: +Inject them at startup. The optional right-hand side renames the variable: ```shell devsy workspace up ... --env LOG_LEVEL --env REGION=AWS_REGION ``` -Use `devsy secret` or an external secret source for sensitive values. `--env` -is deliberately restricted to non-sensitive Devsy-managed values because that -path is not the protected secret-delivery channel. +`--env` accepts only managed environment variables, because it is not the protected delivery path. -Attach a stored variable to the active context to inject it automatically when -workspaces start or are recreated: +Attach a variable to the context to inject it on every start or recreate: ```shell devsy env attach LOG_LEVEL -devsy env list devsy env detach LOG_LEVEL ``` -Attachments are context-scoped and contain only the variable name. The Desktop -Workspace Variables **Environment Variables** tab shows and changes the same -attachment state. Managed environment variables are non-sensitive plaintext -values; use `devsy secret` -for secrets. - -An explicit `devsy workspace up --env LOG_LEVEL` still works for one invocation. -An explicit target, such as `--env LOG_LEVEL=APP_LOG_LEVEL`, overrides the -automatic attachment for that reference and injects the stored value as -`APP_LOG_LEVEL`. Attaching or detaching does not mutate an already-running -workspace; apply changes through the normal workspace start or recreate -lifecycle. - -An attached environment variable must be detached before converting the same -stored name into a secret. Likewise, a locally attached secret must be -detached before converting it into an environment variable. This keeps the -non-sensitive environment path separate from protected secret delivery. If a -stored value is deleted, Devsy removes its context attachment as part of the -same operation. - -Environment-to-secret conversion finishes only after the plaintext entry is -removed. If the process stops between saving the secret and removing that -entry, both stores can contain the name. Restore backend access and retry -`devsy secret set`, or use `devsy env delete` to remove the remaining plaintext -entry. Conversion does not provide crash-atomic recovery across the two stores. - -Sensitive values use `devsy secret attach` instead; attached secrets are -injected through the protected secret-delivery paths described above, and the -Desktop Workspace Variables **Secrets** tab manages their attachment state. +An explicit `--env` with a target overrides the attachment for that run. Attaching or detaching does not change a running workspace. Deleting a value also removes its attachment. + +### Converting between the two + +Detach a name before converting it between an environment variable and a secret. Converting an environment variable to a secret finishes when the plaintext entry is removed. If the process stops midway, the name can exist in both stores. Retry `devsy secret set`, or run `devsy env delete` to remove the plaintext entry. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx index 339fbce524..79487aba22 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/stop-and-delete-a-workspace.mdx @@ -3,72 +3,44 @@ title: Stop or Delete a Workspace sidebar_label: Stop or Delete a Workspace --- -## Stop a Workspace +## Stop a workspace -Stopping a workspace means to temporarily pause a container so that it doesn't consume any more computing resources such as CPU or memory. -Depending on the provider used, this either means to stop a container (see [docker stop](https://docs.docker.com/engine/reference/commandline/stop/) for more information) -or shutdown the underlying VM where the container is running. -Devsy will automatically determine what specific action to take when a workspace is stopped. +Stopping pauses a workspace so it stops using CPU and memory. Depending on the provider, Devsy stops the container or shuts down the VM it runs on. Its data is kept. -### Devsy Desktop +In Devsy Desktop, open the workspace's actions menu and choose **Stop**. With the CLI: -In the 'Workspaces' view, open the actions menu for a running workspace and choose 'Stop'. The workspace immediately shows a **Stopping** status badge. Once stopped, the menu will show a 'Start' option to resume the workspace. Detailed operation progress remains available on the workspace detail surface. - -### Devsy CLI - -Run the following command to stop a workspace: -``` +```sh devsy workspace stop my-workspace ``` -Afterwards, you can start the workspace via: -``` +Start it again with: + +```sh devsy workspace up my-workspace ``` -### Automatic stop - -Some providers allow automatic stop of a workspace, usually to save costs when a workspace is not used. -For example, the Google Cloud provider will shutdown the virtual machine where the workspace is running after it's unused for 10 minutes, by default. -This means you need to start the workspace after it has been stopped when you want to reconnect. - -### Background up tasks +Some providers stop idle workspaces on their own. See [Auto-inactivity timeout](./inactivity-timeout.mdx). -Stopping or deleting a workspace first cancels any active detached `devsy workspace up --detach` task for that workspace, so a background up cannot keep recreating or restarting a workspace you asked to stop. -For current detached workers on Linux, macOS, and Windows, `devsy workspace task cancel ` terminates the task's process tree and records the task as canceled. On other Unix systems, or for older task records without a saved process identity, cancellation can fail when Devsy cannot safely identify surviving processes. -While an SSH tunnel is attached, its health checks observe the workspace but never start a stopped one. +Stopping or deleting a workspace first cancels any running `devsy workspace up --detach` task for it. To cancel a task yourself, use `devsy workspace task cancel `. -## Delete a Workspace +## Delete a workspace -Deleting a workspace means to erase all state of an existing workspace and remove all traces of it within Devsy. -Depending on the Devsy provider, this means either removing a Docker container or deleting a whole virtual machine. -Devsy will automatically determine what specific action to take when a workspace is deleted. +Deleting removes the workspace and everything Devsy stores about it. Depending on the provider, that means removing a container or deleting a VM. -### Devsy Desktop +In Devsy Desktop, open the workspace's actions menu, choose **Delete**, and confirm. If the action fails, the error appears on the workspace detail page, where you can also open the logs. -In the 'Workspaces' view, open the actions menu for the workspace and choose 'Delete', then confirm the deletion dialog. The workspace immediately shows a **Deleting** status badge. The row disappears after deletion finishes and the workspace list confirms removal. Detailed operation progress, errors, and refresh recovery controls remain available on the workspace detail surface. +With the CLI: -Progress for desktop actions stays available when you navigate between pages or reload the window. If the action fails, its error remains visible on the workspace detail surface and you can open the workspace logs for details. If the action finishes but refreshing its status fails, use **Retry refresh** there; this refreshes the observation without repeating the action. - -Live action progress covers commands initiated by the desktop. Commands launched in a separate terminal are reflected by periodic status refreshes. Progress recovery after fully quitting and restarting the desktop is not supported. - -### Devsy CLI - -Run the following command to delete a workspace: -``` +```sh devsy workspace delete my-workspace ``` -`devsy workspace down` (as well as `rm`) is an alias for `devsy workspace delete`. It performs the same full Devsy workspace teardown: -``` -devsy workspace down my-workspace -``` +`devsy workspace down` and `devsy workspace rm` are aliases for the same command. -For Docker Compose-backed workspaces, teardown uses Compose `down` (with `--remove-volumes` remaining an opt-in flag to remove associated named volumes). Use `devsy workspace stop` when you want to stop a workspace while retaining its configuration and state so it can be started again later. +If the provider is unreachable, you can force the delete: -If deletion fails because the Provider is not reachable anymore or another error has occurred, you can also force delete a workspace via: -``` +```sh devsy workspace delete my-workspace --force ``` -However, this means the workspace will only be deleted on the Devsy side locally, and any error raised by the used provider will be ignored. Only use this option with caution as this might leave previously created resources behind. +This only removes the workspace on the Devsy side and ignores provider errors, so it can leave cloud resources behind. diff --git a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/workspace-snapshots.mdx b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/workspace-snapshots.mdx index d00985d46a..411f132e90 100644 --- a/sites/docs-devsy-sh/content/docs/developing-in-workspaces/workspace-snapshots.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-in-workspaces/workspace-snapshots.mdx @@ -3,113 +3,71 @@ title: Workspace Snapshots sidebar_label: Workspace Snapshots --- -## Workspace Snapshots - -A snapshot captures a workspace's working state at a point in time: the running container's filesystem (installed packages, config changes) and the contents of its bind-mounted volumes (your code, including uncommitted changes). Snapshots are stored as OCI artifacts in a registry you control, so you can restore them later, or use them to transfer a workspace to a different provider. +A snapshot captures a workspace at a point in time: the container's filesystem, such as installed packages and config changes, and the contents of its bind-mounted volume, including uncommitted code. Snapshots are stored as OCI artifacts in a registry you control. You can restore one later or use it to move a workspace to another provider. -Snapshots are pushed to and pulled from an OCI registry (Docker Hub, GHCR, ECR, or a self-hosted `registry:2`), not stored locally. You need push/pull access to a registry before creating one. +Snapshots are pushed to and pulled from an OCI registry, not stored locally. You need push and pull access to one. -## Create a Snapshot - -The workspace must already be running (`devsy workspace up` must have created it, so its mount information is available): - -```sh -devsy snapshot create my-workspace --registry ghcr.io/my-org/snapshots -``` +## Limitations -On success, the command prints the snapshot ref, which you'll use to restore it later: +- Only workspaces with exactly one bind mount are supported. +- Only local providers, such as Docker and Podman, can create snapshots. Machine-provider workspaces cannot. -``` -ghcr.io/my-org/snapshots:my-workspace-20260731150405-x7f2qk -``` +## Create a snapshot -Add `--message` to describe the snapshot: +The workspace must already exist and be running. ```sh -devsy snapshot create my-workspace --registry ghcr.io/my-org/snapshots --message "before the auth refactor" +devsy snapshot create my-workspace --registry ghcr.io/my-org/snapshots ``` -### Default Registry +The command prints the snapshot reference, which you need to restore it. Add `--message` to describe the snapshot. -Rather than passing `--registry` every time, set a default for the current context: +To avoid passing `--registry` each time, set a default for the context: ```sh devsy context set -o SNAPSHOT_REGISTRY=ghcr.io/my-org/snapshots ``` -### Limitations - -- Only workspaces with exactly one bind mount are supported today. Workspaces with multiple mounts (e.g. an extra `mounts` entry in `devcontainer.json`) aren't yet supported. -- Only local providers (Docker, Podman) can create snapshots. Machine-provider workspaces aren't supported. - -## List Snapshots +## List snapshots ```sh devsy snapshot list my-workspace --registry ghcr.io/my-org/snapshots ``` -Shows every snapshot pushed for that workspace, newest first. +This shows every snapshot of that workspace, newest first. -## Restore a Snapshot +## Restore a snapshot ```sh -devsy snapshot restore ghcr.io/my-org/snapshots:my-workspace-20260731150405-x7f2qk +devsy snapshot restore ``` -This creates a new workspace from the snapshot's committed filesystem and volumes, skipping the devcontainer build entirely since the image is already built. By default the new workspace reuses the original workspace ID; pass `--workspace-id` to restore under a different one, or `--target-provider` to restore using a different provider than the one the snapshot was taken from. +This creates a workspace from the saved filesystem and volume and skips the devcontainer build. It reuses the original workspace ID. Use `--workspace-id` to pick another one, or `--target-provider` to restore onto a different provider. -Equivalently, you can restore as part of `devsy workspace up`: +You can also restore as part of `devsy workspace up`. This cannot be combined with a source argument or `--source`. ```sh -devsy workspace up --from-snapshot ghcr.io/my-org/snapshots:my-workspace-20260731150405-x7f2qk +devsy workspace up --from-snapshot ``` -`--from-snapshot` can't be combined with a positional source or `--source`. - -### Transferring Between Providers +To move a workspace to another provider, restore its snapshot with `--target-provider`. -To move a workspace to a different provider, restore its snapshot with `--target-provider`: +## Delete a snapshot ```sh -devsy snapshot restore ghcr.io/my-org/snapshots:my-workspace-20260731150405-x7f2qk --target-provider kubernetes +devsy snapshot delete ``` -## Delete a Snapshot - -```sh -devsy snapshot delete ghcr.io/my-org/snapshots:my-workspace-20260731150405-x7f2qk -``` - -Removes the snapshot's manifest from the registry. The underlying image and volumes blobs are left for the registry's own garbage collection. - -## Export and Import - -`devsy workspace export`/`devsy workspace import` automatically carry a workspace's snapshot ref when the workspace was itself restored from one, so exporting and re-importing a snapshot-sourced workspace preserves its actual filesystem and volume state, not just its metadata - provided the snapshot manifest is still present in the registry and the environment doing the import has access to pull that registry artifact. If the manifest has been deleted or the import environment can't reach or authenticate to the registry, only the workspace's metadata carries over, not its filesystem/volume state. - -## Identifying Snapshot Images +This removes the manifest from the registry. The registry's own garbage collection removes the image and volume blobs. -The container image a snapshot commits is tagged `LABEL sh.devsy.snapshot=true`, so it can be identified with `docker inspect` or filtered with `docker images --filter label=sh.devsy.snapshot` even outside `devsy snapshot` tooling. +## Export and import -## Volume filtering +`devsy workspace export` and `devsy workspace import` carry the snapshot reference for a workspace that was restored from one. The import restores the real filesystem and volume only if the manifest still exists and the importing machine can pull from the registry. Otherwise only the workspace metadata carries over. -`.devsyignore` rules do not apply to the committed container image. +## What is included -When Devsy captures host bind mounts, `.devsyignore` applies only to the explicitly -designated workspace mount, relative to that source root. The streaming protocol -keeps additional bind mounts independent of those rules. -The snapshot CLI currently requires a single workspace mount because restore -cannot disambiguate multiple mounts. +The committed container image carries the label `sh.devsy.snapshot=true`, so you can find it with `docker images --filter label=sh.devsy.snapshot`. -Files excluded from the workspace volume are absent from the snapshot and from a -restore into an empty or reset target. Without `--reset`, Devsy skips restoring a -target that already contains workspace files and retains its existing contents. -A missing ignore file applies no user exclusions; an invalid or unreadable existing file -stops snapshot streaming. Snapshot creation loads persisted workspace metadata, -which does not grant generated-file transfer exceptions. Devsy excludes its generated -`.devsy-internal` directory at the configured build context, including files left -behind by an interrupted build or failed cleanup. Unrelated folders with that name -follow the workspace ignore rules. Missing build-context metadata stops snapshot -creation; run `devsy up` to refresh it. Tar target prefixes and the volume restore -format are unchanged. +`.devsyignore` rules apply to the workspace mount and not to the container image. Files they exclude are missing from the snapshot. If snapshot creation reports missing build-context metadata, run `devsy up` to refresh it. diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/agent.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/agent.mdx index 8c16fe6679..8d055f05a4 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/agent.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/agent.mdx @@ -3,32 +3,15 @@ title: Provider Agent sidebar_label: Provider Agent --- -When Devsy connects through a Provider to an environment, it will inject itself into the environment to handle the following tasks: -- deploying the container -- forward credentials -- ssh server -- auto-shutdown after a period of inactivity +When Devsy connects to an environment through a provider, it injects itself there. This counterpart is the Devsy agent. It is the same binary, run as `devsy agent`. The agent deploys the container, forwards credentials, runs the SSH server and stops idle environments. -This counterpart is called the Devsy agent, which is available in the same Devsy binary under `devsy agent`. -Within the `provider.yaml` you can configure certain parts of how local Devsy should interact with its agent counterpart. - - -Agent's **Driver** specifies how the whole container workload is deployed inside -the provider's resources. - -Head over to the [drivers section](./driver.mdx) to understand how this impacts -the provider - - -## Agent section - -The following options are available in the `agent` section +The `agent` section of `provider.yaml` controls how Devsy works with it. ```yaml -agent: # You can also use options within this section (see injectGitCredentials as an example) +agent: path: ${DEVSY} - local: true # Optional, whether Devsy runs directly on this machine (no remote agent injection) - driver: docker # Optional, default: docker. One of: docker, kubernetes, apple, microsandbox, custom + local: true + driver: docker inactivityTimeout: 10m containerInactivityTimeout: 10m injectGitCredentials: ${INJECT_GIT_CREDENTIALS} @@ -37,54 +20,32 @@ agent: # You can also use options within this section (see injectGitCredentials MY_BINARY: - os: linux arch: amd64 - path: https://url-to-binary.com - checksum: shasum-of-binary + path: https://example.com/my-binary + checksum: exec: shutdown: |- ${MY_BINARY} stop ``` -Breaking down the options: - -- **path**: where to place the agent on the remote machine. This controls the agent's location; running on the local machine instead is controlled by the separate **local** field below, not by the value of `path`. -- **local**: if true, signals that Devsy is running directly on the current machine (as opposed to a remote VM or container reached over SSH). All of Devsy's built-in providers (`docker`, `podman`, `kubernetes`, `apple`, `microsandbox`) set this to `true`. -- **driver**: which driver to use to run the container, [check the Drivers section for more information](./driver.mdx) -- **inactivityTimeout**: after how much time to shut down the machine. Use for machine providers -- **containerInactivityTimeout**: after how much time to shut down the container. Use for non-machine providers -- **injectGitCredentials**: whether to inject git credentials into the machine. -- **injectDockerCredentials**: whether to inject docker credentials into the machine. -- **exec.shutdown**: command to execute when shutting down the machine after Devsy has determined the `inactivityTimeout`. Option values will be available here as well. For example, you can reuse an option that stores a cloud api key within this command to terminate the machine. -- **binaries**: this section can be used to declare additional binaries to download on the machine to use in `exec.shutdown` - - -The `binaries` section is useful for injecting a helper binary in the machine, in order to -use the specific cloud's APIs to shut down the machine, if a simple `shutdown -h now` does not work - - - -The `binaries` section follows the same syntax and structure of the [binaries section in the main provider manifest](./binaries.mdx) - - -## Auto-Inactivity Stop +Option values can be used in this section. -One of the most important features of Devsy is to make sure that developer environments use as little resources as possible when they are not used. +- **path**: where the agent is placed on the remote machine. +- **local**: set to `true` when Devsy runs directly on this machine instead of reaching a remote one. The built-in providers do this. +- **driver**: how the container is deployed. One of `docker` (default), `kubernetes`, `apple`, `microsandbox`, `custom` or `external`. See [Drivers](./driver.mdx). +- **inactivityTimeout**: how long to wait before stopping an idle machine. For machine providers. +- **containerInactivityTimeout**: how long to wait before stopping an idle container. For non-machine providers. +- **injectGitCredentials**, **injectDockerCredentials**: whether to copy those credentials into the environment. +- **exec.shutdown**: the command that stops the machine once it is idle. Option values are available in it. +- **binaries**: helper binaries for `exec.shutdown`. Same format as [provider binaries](./binaries.mdx). -### Non-Machine Providers +## Stopping idle environments -For non-machine providers, Devsy can automatically kill the container it's running in by terminating the process with pid 1. This is useful for providers such as docker, podman, kubernetes or ssh, where you don't want the container to be running if it's not needed. The timeout can be configured through `agent.containerInactivityTimeout`. Devsy will then start a process within the container to keep track of activity and then kill itself when the user hasn't connected for the given duration. This will not erase any state within the container and instead only stop it. Then when the user wants to start working with the workspace again, Devsy will start the container again. +Devsy tracks whether anyone is connected and stops the environment after the timeout. Nothing is erased. Devsy starts it again when the user returns. -### Machine Providers +### Non-machine providers -For machine providers, killing just the container within the remote machine is typically not enough as VMs still generate costs even if they are unused. -Hence Devsy provides a way to configure automatically shutting down or deleting an unused machine on the cloud provider side if a developer is currently not working anymore. -Devsy will then restart or recreate it again, when the development should continue. +The agent ends the container's main process, which stops the container. Set the timeout with `containerInactivityTimeout`. -Devsy tries to make this as easy as possible for you, as it will automatically keep track of when a user is connected to a workspace or not and only needs the command to run when the machine should be stopped from the provider. -This command can be defined through `agent.exec.shutdown`. -All configured options are available in this command and helper binaries needed can be defined through `agent.exec.binaries` +### Machine providers -Official providers that use this method of automatically stopping an inactive machine are: -- [devsy-provider-azure](https://github.com/devsy-org/devsy-provider-azure): Just uses `shutdown -t now` as `agent.exec.shutdown` to shutdown an unused machine. -- [devsy-provider-aws](https://github.com/devsy-org/devsy-provider-aws): Uses the local `aws` cli tool to generate a temporary token, which is then saved in a Devsy option. This token is then used within `agent.exec.shutdown` to shutdown the machine on the agent side with an AWS api call. -- [devsy-provider-gcloud](https://github.com/devsy-org/devsy-provider-gcloud): Uses the local `gcloud` cli tool to generate a temporary token, which is then saved in a Devsy option. This token is then used within `agent.exec.shutdown` to shutdown the machine on the agent side with an Google Cloud api call. -- [devsy-provider-digitalocean](https://github.com/devsy-org/devsy-provider-digitalocean): Deletes the whole machine on inactivity as stopped machines are still billed by DigitalOcean. The local digital ocean token is reused on the agent side to make an API call to delete the whole machine and preserve the state in an extra volume. +Stopping only the container would leave the VM running and billed. Define `agent.exec.shutdown` with the command that stops or deletes the machine on the cloud side. Set the timeout with `inactivityTimeout`. The official cloud providers each do this their own way, for example with a cloud API call using a token saved in an option. diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/binaries.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/binaries.mdx index bbb37f8d26..b6cefee3a0 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/binaries.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/binaries.mdx @@ -3,121 +3,62 @@ title: Provider Binaries sidebar_label: Provider Binaries --- -The `binaries` section can be used to specify helper binaries Devsy should download that help the provider to accomplish its tasks. +The `binaries` section lists helper binaries Devsy downloads for a provider, such as a cloud CLI. -An example of this type of provider are: - -- [devsy-provider-aws](https://github.com/devsy-org/devsy-provider-aws/releases) -- [devsy-provider-azure](https://github.com/devsy-org/devsy-provider-azure/releases) -- [devsy-provider-civo](https://github.com/devsy-org/devsy-provider-civo/releases) -- [devsy-provider-digitalocean](https://github.com/devsy-org/devsy-provider-digitalocean/releases) -- [devsy-provider-gcloud](https://github.com/devsy-org/devsy-provider-gcloud/releases) - -Each binary that is required is declared through: +Each entry is a name with one item per platform: ```yaml binaries: - NAME: - - os: # Which OS is this specific binary - arch: # Binary arch - path: # Remote (URL) or local path to binary - checksum: # sha sum of the binary - archivePath: # If it's an archive, the relative path to the binary. Supported archives are .tgz, .tar, .tar.gz, .zip - name: # Optional name to store the binary as locally. Defaults to the file name derived from path. -``` - -When [Adding a provider](../managing-providers/manage-providers.mdx), Devsy will -match the binary for your OS and Arch and download the specific one for it. - - -Not every provider needs a `binaries` section. Built-in providers that wrap an -already-installed local CLI - such as `docker`, `apple` (the `container` CLI) or -`microsandbox` - instead expose an option (e.g. `DOCKER_PATH`, `CONTAINER_PATH`) -pointing to the binary the user already has on their machine, rather than -downloading one. Use `binaries` when your provider needs to fetch and manage its -own helper binary. - - -Example of the binary section in a `provider.yaml`: - -```yaml -binaries: - AWS_PROVIDER: - - os: linux - arch: amd64 - path: https://github.com/devsy-org/devsy-provider-aws/releases/download/v0.0.1-alpha.15/devsy-provider-aws-linux-amd64 - checksum: d1e774419d90c3ed399963d9322d57bfdcee189767eabb076a2c2e926bfd9b8b + MY_BINARY: - os: linux - arch: arm64 - path: https://github.com/devsy-org/devsy-provider-aws/releases/download/v0.0.1-alpha.15/devsy-provider-aws-linux-arm64 - checksum: fa15c13e3f0619170d002f9dae3ef41c9949a4595a71c5efe364d89ada604cec - - os: darwin arch: amd64 - path: https://github.com/devsy-org/devsy-provider-aws/releases/download/v0.0.1-alpha.15/devsy-provider-aws-darwin-amd64 - checksum: fb89d41f6ce3e01e953f3ffd18f85bd5a42dd633abafd5d586dc9d9b1322166c + path: https://example.com/my-binary-linux-amd64 # URL or local path + checksum: + archivePath: bin/my-binary # only if path is an archive + name: my-binary # optional, defaults to the file name - os: darwin arch: arm64 - path: https://github.com/devsy-org/devsy-provider-aws/releases/download/v0.0.1-alpha.15/devsy-provider-aws-darwin-arm64 - checksum: 82b6713069fa061ea59941600ed32a15f73806a9af3074d67a20ed367d18b2aa - - os: windows - arch: amd64 - path: https://github.com/devsy-org/devsy-provider-aws/releases/download/v0.0.1-alpha.15/devsy-provider-aws-windows-amd64.exe - checksum: 49bd899d439f38d4e8647102db1c18b7a0d5242b3c09c89071b20a5444e20a81 + path: https://example.com/my-binary-darwin-arm64 + checksum: ``` -### Binary Checksum +Supported archives are `.tgz`, `.tar`, `.tar.gz` and `.zip`. When a user adds the provider, Devsy picks the item that matches their OS and architecture, downloads it and verifies the checksum. -Each binary is also verified over an expected checksum. This is important to -ensure that whatever binary is declared in `provider.yaml` is indeed executed on -the machine. +See the official providers, such as [devsy-provider-aws](https://github.com/devsy-org/devsy-provider-aws), for complete examples. + + +Not every provider needs `binaries`. Built-in providers that wrap a CLI the user already has, such as `docker`, expose an option like `DOCKER_PATH` instead of downloading one. + -## Use binaries in commands +## Use a binary -Devsy will make the binary path available through an environment variable within the exec section. For example: +Devsy exposes each binary's path as an environment variable with the same name. -```yaml -binaries: - MY_BINARY: - .... +In `exec`: +```yaml exec: init: ${MY_BINARY} init - .... ``` -## Use binaries in options - -You can also use binaries within the option `command` attribute. For example: - - ```yaml - binaries: - MY_BINARY: - .... - - options: - MY_OPTION: - command: ${MY_BINARY} retrieve-option - ``` +In an option `command`: -## Use binaries on the agent side +```yaml +options: + MY_OPTION: + command: ${MY_BINARY} retrieve-option +``` -You can also define binaries Devsy should install on the agent side through `agent.binaries`. These binaries can then be used within the `agent.exec` section to automatically stop a virtual machine if inactive. -For example: +On the agent side, declare the binary under `agent.binaries` and use it in `agent.exec`: ```yaml agent: - path: ${AGENT_PATH} binaries: - GCLOUD_PROVIDER: + MY_BINARY: - os: linux arch: amd64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-linux-amd64 - checksum: 38f92457507563ee56ea40a2ec40196d12ac2bbd50a924d76f55827e96e5f831 - - os: linux - arch: arm64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-linux-arm64 - checksum: 48e8dfa20962f1c3eb1e3da17d57842a0e26155df2b94377bcdf5b8070d7b17e + path: https://example.com/my-binary-linux-amd64 + checksum: exec: - shutdown: |- - ${GCLOUD_PROVIDER} stop --raw + shutdown: ${MY_BINARY} stop ``` diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/driver.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/driver.mdx index c51edc1ce2..1045907240 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/driver.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/driver.mdx @@ -3,117 +3,9 @@ title: Drivers sidebar_label: Drivers --- -In Devsy you can specify a **Driver** in the [Agent's configuration](./agent.mdx). +A driver decides how Devsy deploys the workspace container. Set it with `driver` in the [agent section](./agent.mdx). The default is `docker`. -A Driver indicates how Devsy deploys the workspace container. - -Devsy currently supports five built-in driver types: - -- Docker driver -- Kubernetes driver -- Apple driver -- Microsandbox driver -- Custom driver - -The provider schema also accepts [external runtime declarations](#external-runtime-declarations-under-development). -Their host adapter is under development. - - -If no driver is specified, the default is **Docker** - - -## External runtime declarations (under development) - -The provider schema accepts `agent.driver: external` and validates the configuration -when the provider is installed. Devsy launches the declared runtime through the -workspace driver factory and negotiates its Runtime Protocol v1 capabilities. - -```yaml -agent: - driver: external - external: - binary: RUNTIME_DRIVER - args: ["serve"] - imageBackend: docker - binaries: - RUNTIME_DRIVER: - - os: linux - arch: amd64 - path: https://example.com/runtime-driver - checksum: "<64 hexadecimal characters: SHA-256 of the extracted executable>" -``` - -`binary` is the exact key in `agent.binaries`, not an executable path or a name to -search on `PATH`. Each declared platform requires a SHA-256 checksum and must -appear only once. Declare the agent's OS and architecture, which may differ from -the desktop's platform. The runtime must already be prepared in the agent binary -directory; the resolver verifies its checksum and never downloads or removes files. -A declared local absolute path is also verified. - -`args` is a static argument array, with no shell or option substitution. Its first -entry cannot be empty; later empty arguments are preserved. `imageBackend` accepts -`docker` (the default) or `none`; it selects the Devsy-side image backend, -not an image-building capability in the runtime plugin. - -For the protocol and SDK contract, see [Runtime Protocol v1](./runtime-protocol.mdx). - -### Runtime and image integration - -The internal host now negotiates Runtime Protocol v1 Info and performs preflight, -Find, TargetArchitecture, RunImage, Start, Stop, and Delete calls. Each operation -uses a fresh plugin process owned by the SDK supervisor, exposed through a -hidden helper in the running Devsy executable. Cancellation also covers startup -and terminates the leased process tree. The workspace runner uses the external -runtime for lifecycle and execution, and a separate Docker image backend for -inspection, builds, tagging, and publication. Docker settings use `agent.docker`. -Selecting `none` skips Docker backend construction; ordinary builds retain the -existing dockerless fallback, while prebuild publication requires an image backend. - -Run options preserve image identity, entrypoint, literal arguments, environment, -labels, privilege/init presence, namespace mappings, platform, and mount options. -CPU, memory, storage, and GPU requirements are translated into protocol values. -Invalid sizes, unsupported mount types, Compose external volumes, raw `runArgs`, -`appPort` mappings (use port forwarding instead), and GPU core or -memory requirements that v1 cannot express are rejected before runtime creation. -During recreation, validation happens before stopping or removing the existing -workspace. Mount streaming, workspace ownership, and recreate policy follow the -negotiated runtime capabilities; in-place reprovisioning remains unsupported. - -The host also supports binary-safe Exec with separate stdout/stderr, literal argv, -stdin closure, and terminal exit status. Shell commands use `/bin/sh -c`; text -stdout and stderr are redacted, while `RawStdout` and argv execution preserve raw -stdout for protocol consumers. Logs capability is checked before launch and its -merged binary stream is written to stdout. - -The host retains environment values supplied through RunImage for that workspace -throughout its lifetime, including prior values from retries or failed requests. -Retention belongs to the current workspace runner and is released with that host; -it is not a persisted secret store and does not survive a new CLI process. Runtime -plugins must keep diagnostics safe when values are not available to a new host. -Later text output, errors, and diagnostics use that workspace's redaction snapshot; -raw stdout and merged Logs remain binary streams for their callers to handle. - -Once Exec streaming starts, the host closes closable stdin on completion or -cancellation. Blocking input must unblock when closed or when the caller context -is canceled, and output writers must return from writes. Go cannot interrupt an -arbitrary blocking reader or writer. The host joins the input pump and reaps the -owned plugin session before returning. - -The host inherits its environment for compatibility with proxy, certificate, -HOME/XDG, Docker, and runtime CLI settings. Provider environment overrides and -the verified runtime binary key are forwarded; plugin transport metadata keeps -precedence. Arguments are passed literally without shell expansion, and -text diagnostics are redacted before logging. - -Before every operation the host rechecks the prepared runtime's checksum and -permissions. Relative declarations also reject symlink targets outside their -binary directory; explicit absolute declarations retain their documented -behavior. These checks do not provide a filesystem sandbox or atomic -verification-to-execution guarantee. The runtime and its directories must be -trusted. Unix command descendants must remain in the supervised process group -and retain signalable privileges; detached or elevated services need their own -owner. Real-runtime compatibility and startup measurements against a complete -workspace launch remain gates before runtime cutover or session reuse. +Built-in drivers: `docker`, `kubernetes`, `apple`, `microsandbox` and `custom`. A sixth, `external`, runs a runtime plugin and is [described below](#external-driver). ## Docker Driver @@ -238,73 +130,18 @@ agent: ## Microsandbox Driver -The Microsandbox driver boots the devcontainer image as a hardware-isolated -microVM (via [libkrun](https://github.com/containers/libkrun)) using the -[microsandbox](https://github.com/microsandbox/microsandbox) runtime. This is -the driver used by the built-in `microsandbox` provider. +The Microsandbox driver boots the devcontainer image as a hardware-isolated microVM using [microsandbox](https://github.com/microsandbox/microsandbox). It is used by the built-in `microsandbox` provider. -Available options: -- **memory**: guest memory limit in MiB. Empty uses the runtime default. -- **cpus**: number of virtual CPUs. Empty uses the runtime default. -- **maxMemory**: hotplug memory ceiling in MiB. Empty uses the runtime default. -- **maxCpus**: hotplug CPU ceiling. Empty uses the runtime default. -- **storage**: OCI root disk size in GiB. Empty uses the runtime default, falling - back to the devcontainer's `hostRequirements.storage` when set. -- **blockEgress**: if true, deny the microVM outbound public network access (sandbox hardening). -- **ephemeral**: if true, boot from a tmpfs root disk so the microVM's disk - state is discarded when it stops. Sized by `storage`/`hostRequirements.storage`, - or 8GiB if neither is set. -- **workspaceHostPermissions**: controls chmod behavior for the primary workspace - bind mount. `mirror` (the default) mirrors guest rwx changes to the host; - `private` keeps them in MicroSandbox metadata. -- **workspaceStatVirtualization**: controls workspace ownership and metadata - virtualization. `strict` (the default) requires compatible host metadata - support; `relaxed` tolerates filesystems without it; `off` exposes literal - host ownership and modes. `off` cannot be combined with `mirror`. - -The primary workspace bind mount uses `stat-virt=strict` and `host-perms=mirror` -by default, while additional bind mounts retain MicroSandbox's defaults. -`containerUser` controls the workload execution user; `remoteUser` controls the -workspace developer identity, falling back to `containerUser`, the image user, -and then root. Devsy resolves the developer's numeric UID and primary GID from -the final image's account files and sets them as the mount's guest-visible -fallback owner. These IDs apply to host-created entries without per-file guest -metadata; they do not change host inode ownership. Account resolution does not -execute image code. An unresolvable user fails provisioning before replacement -of the existing VM. With `workspaceStatVirtualization: "off"`, Devsy omits the -owner override. - -In Dockerless mode, the developer filesystem is built inside the VM after its -workspace mount is created. Ownership synchronization therefore supports only -`remoteUser: "root"` in this mode. Other identities fail before replacing an -existing VM. For a non-root developer, use a prebuilt image or explicitly select -`workspaceStatVirtualization: "off"` with private host permissions. Devsy never -looks up the developer account in the unrelated Dockerless runner image. - -Image inspection and preparation prefer an image cached in the configured -Docker-compatible CLI, permitting offline/private-registry startup. Preparation -freezes the final image before account resolution and import. Both use that same -snapshot, imported under a content-derived tag, so retagging the original image -cannot change the imported filesystem or its fallback owner. Registry-only -images do not require Docker initialization. - -Devsy-managed workspaces with an incompatible persisted workspace mount contract -require explicit `devsy up --recreate`, including workspaces created before the -contract label existed. Changing workspace permission policy or the effective -developer identity also requires explicit recreation. Ordinary `devsy up` reports -an actionable error and preserves the existing VM. Back up VM-local data before -recreating: the host workspace and named volumes persist, but the VM root disk -is discarded. Replacement cannot roll back failures after removal. -Externally managed containers cannot be replaced through this flow. - -Devsy requires MicroSandbox v0.7.2 or newer when creating or recreating workspaces -that use workspace ownership synchronization. Runtime compatibility, account -resolution, final image import, and volume preparation complete before removing -an existing VM. -The provisioning version check does not block inspection, logs, stop, or deletion -of an existing sandbox. -Apple Silicon macOS is the canonical supported integration-test host; use -`relaxed` when a host filesystem cannot provide strict metadata virtualization. +Options: +- **memory**, **cpus**: guest memory in MiB and virtual CPU count. Empty uses the runtime default. +- **maxMemory**, **maxCpus**: ceilings for hotplugged memory and CPUs. +- **storage**: root disk size in GiB. Falls back to the devcontainer's `hostRequirements.storage`. +- **blockEgress**: deny the microVM outbound public network access. +- **ephemeral**: boot from a tmpfs root disk, so disk state is discarded when the VM stops. +- **workspaceHostPermissions**: `mirror` (default) mirrors guest permission changes on the workspace mount to the host. `private` keeps them in microsandbox metadata. +- **workspaceStatVirtualization**: `strict` (default) requires host metadata support. `relaxed` tolerates filesystems without it. `off` exposes literal host ownership and modes, and cannot be combined with `mirror`. + +Changing the workspace permission policy or the developer identity requires `devsy up --recreate`. The VM root disk is discarded on recreate, so back up VM-local data first. The host workspace and named volumes persist. ```yaml agent: @@ -313,27 +150,41 @@ agent: microsandbox: memory: "2048" blockEgress: "false" - ephemeral: "false" - workspaceHostPermissions: "mirror" workspaceStatVirtualization: "strict" ``` ## Custom Driver -The custom driver lets a provider fully own how the devcontainer lifecycle is -implemented, by supplying its own shell commands instead of relying on -Devsy's built-in Docker, Kubernetes, Apple or Microsandbox integration. - -When `driver: custom` is set, the following commands become required under -`agent.custom`: -- **findDevContainer**: locate an existing devcontainer -- **commandDevContainer**: execute a command inside the devcontainer -- **targetArchitecture**: determine the target architecture -- **runDevContainer**: run the devcontainer -- **startDevContainer**: start the devcontainer -- **stopDevContainer**: stop the devcontainer -- **deleteDevContainer**: delete the devcontainer - -The optional **getDevContainerLogs** command retrieves devcontainer logs, and -**canReprovision** signals whether the driver supports reprovisioning the -devcontainer in place. +The custom driver lets a provider implement the devcontainer lifecycle with its own shell commands. With `driver: custom`, these commands are required under `agent.custom`: + +- **findDevContainer**: find an existing devcontainer. +- **commandDevContainer**: run a command inside it. +- **targetArchitecture**: print the target architecture. +- **runDevContainer**, **startDevContainer**, **stopDevContainer**, **deleteDevContainer**: run, start, stop and delete it. + +Optional: **getDevContainerLogs** prints the logs, and **canReprovision** says whether the devcontainer can be reprovisioned in place. + +## External Driver + +`driver: external` runs a runtime plugin that speaks [Runtime Protocol v1](./runtime-protocol.mdx). + +```yaml +agent: + driver: external + external: + binary: RUNTIME_DRIVER + args: ["serve"] + imageBackend: docker + binaries: + RUNTIME_DRIVER: + - os: linux + arch: amd64 + path: https://example.com/runtime-driver + checksum: "" +``` + +- **binary**: the exact key in `agent.binaries`. It is not a path and is never searched on `PATH`. +- **args**: a fixed argument list. No shell or option substitution is applied. +- **imageBackend**: `docker` (default) or `none`. It picks the Devsy-side image backend, not a build capability in the plugin. With `none`, prebuild publishing is unavailable. + +Each platform needs a SHA-256 checksum, and the runtime must already be in the agent binary directory. Devsy verifies the checksum before every operation and never downloads or removes the file. The plugin is trusted provider code and runs with the same access as Devsy. diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/options.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/options.mdx index 2995c50d5d..e6da30f982 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/options.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/options.mdx @@ -3,216 +3,86 @@ title: Provider Options sidebar_label: Provider Options --- -Inside the [`provider.yaml`](./quickstart.mdx#provideryaml), you can specify options -that Devsy can pass to the provider when calling it. -Each option will be passed as an environment variable to the commands or can be used directly inside the `agent` section of a provider. +Options are settings the user can configure for a provider, such as an account, region, VM size or image. Define them in [`provider.yaml`](./quickstart.mdx#sections-of-provideryaml): ```yaml -... -... options: - MY_OPTION_NAME: + MY_OPTION: description: "this is my option" default: "default_value" required: false password: true -... -... ``` -## How options work +Devsy validates options when the provider is added and passes them to every command as environment variables. They can also be used in the `agent` section and in `agent.exec`. The provider is responsible for reading and validating its own variables. Put that check in the `init` command, which Devsy runs when options change. -Options are variables needed for the provider to function properly, for example: +## Attributes -- User Accounts -- VMs images -- VMs sizes -- Account region +- `displayName`: name shown by tools such as the Desktop app, instead of the option name. +- `description`: shown by `devsy provider get` and in the Desktop app. +- `default`: default value, as a string. It can reference other options, for example `${OTHER}-suffix`. Devsy resolves them in the right order. +- `required`: the value must be non-empty. Devsy prompts for it in the CLI, and the Desktop app asks for it. +- `password`: treat the value as a secret. It is hidden in `devsy provider get` and entered in a password field in the Desktop app. +- `type`: `string` (default), `multiline`, `duration`, `number` or `boolean`. Devsy validates the value against it. +- `enum`: the only allowed values. Devsy rejects anything else. +- `suggestions`: values offered as autocomplete in the Desktop app. Not enforced, and not shown in the CLI. +- `validationPattern`: regex the value must match. +- `validationMessage`: error shown when the pattern does not match. A generic message is used if empty. +- `command`: command that fills the value. It can reference other options. On Windows it runs in an emulated shell. +- `subOptionsCommand`: command that prints more `options`, in the same YAML shape, based on other option values. +- `local`: fill the option separately for each machine or workspace. +- `global`: reuse the option for every machine or workspace. Cannot be combined with `cache` or `mutable`. +- `cache`: re-run `command` after this duration, for example `5m`. Use it for values that expire, such as tokens. +- `hidden`: hide the option in the Desktop app and `devsy provider get`. Use it for internal values. +- `mutable`: allow changing the value on an existing machine or workspace. Cannot be combined with `global`. -These options are parsed and validated by Devsy when [Adding the provider](../managing-providers/manage-providers.mdx) -and passed to the provider as **environment variables**. - -It's the provider's job to retrieve them from the environment and validate them. -It's recommended to make use of the `init` command that will be called by Devsy when options change to validate environment variables on the provider side. - -You can check our example in the [Devsy's AWS Provider](https://github.com/devsy-org/devsy-provider-aws/blob/main/pkg/options/options.go#L44) -where we parse and validate the variables: - -```go -... - diskSizeGB, err := fromEnvOrError("AWS_DISK_SIZE") - if err != nil { - return nil, err - } - - retOptions.DiskSizeGB, err = strconv.Atoi(diskSizeGB) - if err != nil { - return nil, err - } -... -``` - -Options will also be passed to the agent and can be used in the `agent.exec` section. This is very useful if you require certain information on the agent side to perform an auto-inactivity timeout. - -### Option configuration - -Each option has a set of attributes that can modify how Devsy interprets it when -configuring or adding the provider: - -- `displayName`: Display name of the option, preferred over the option name by a supporting tool such as the Desktop App. -- `description`: Description shown in `devsy provider get` and in the Desktop App -- `default`: Default value of the option provided as a string. Can also reference other variables, e.g. `${MY_OTHER_VAR}-suffix` -- `required`: Boolean if this option needs to be non-empty before using the provider. Devsy will ask in the CLI and make sure that this option is filled in the Desktop application. -- `password`: Boolean to indicate this is a sensitive value. Prevents this value from showing up in the `devsy provider get` command and will be a password field in the Desktop application. -- `type`: The option type. One of `string`, `multiline`, `duration`, `number` or `boolean`. Defaults to `string`. Devsy validates the value against the given type. -- `enum`: A list of allowed values for this option. Unlike `suggestions`, this is enforced - Devsy will reject any value that isn't in the list. -- `validationPattern`: A regex pattern the value must match. -- `validationMessage`: The error message shown when `validationPattern` doesn't match. If not specified, Devsy shows a generic message including the pattern. -- `suggestions`: An array of suggestions for this option. Will be shown as auto complete options in the Devsy desktop application -- `command`: A command to retrieve the option value automatically. Can also reference other variables in the command, e.g. `echo ${MY_OTHER_VAR}-suffix`. For compatibility reasons, this command will be executed in an emulated shell on Windows. -- `subOptionsCommand`: A command that outputs additional `options` (in the same YAML shape as the top-level `options` section) to dynamically extend the provider's option set based on other option values. -- `local`: If true, the option will be filled individually for each machine / workspace -- `global`: If true, the option will be reused for each machine / workspace. Cannot be combined with `cache` or `mutable`. -- `cache`: If non-empty, Devsy will re-execute the command after the given timeout, e.g. if this is 5m, Devsy will re-execute the command after 5 minutes to re-fill this value. This is useful if you want to store a token or something that expires locally in a variable. -- `hidden`: If true, Devsy will not show this option in the Desktop application or through `devsy provider get`. Can be used to calculate variables internally or save tokens or other things internally. -- `mutable`: If true, the option's value can be changed on an existing workspace or machine after creation. Cannot be combined with `global`. - -### Default values - -As the name implies, this is a default value for the option. It is always advisable -to place a sensible default for any option. - -You can also reference other options inside the default value, e.g. `${MY_OTHER_VAR}-suffix`. Devsy will automatically figure out what options need to be resolved before this option. - -**If not specified, it defaults to an empty string**. - -### Required options - -If an option is required, and no default is set, Devsy will prompt the user for -a value when adding the provider. - -In the Devsy Desktop App, the required options will be displayed and prompted -right in the Provider's "Add" page. - -**If not specified, it defaults to false**. - -### Password options - -If specified and true, the option's value will be treated as a secret, so it -won't be shown when listing options. - -Example: - -```sh -~$ devsy provider get civo - - NAME | REQUIRED | DESCRIPTION | DEFAULT | VALUE -----------------------------+----------+--------------------------------+--------------------------------------+--------------------------------------- -AGENT_PATH | false | The path where to inject the | /var/lib/toolbox/devsy | /var/lib/toolbox/devsy - | | Devsy agent to. | | -CIVO_API_KEY | true | The civo api key to use | | ******** -CIVO_DISK_IMAGE | false | The disk image to use. | d927ad2f-5073-4ed6-b2eb-b8e61aef29a8 | d927ad2f-5073-4ed6-b2eb-b8e61aef29a8 - -... -``` - -**If not specified, it defaults to false**. - -### Options suggestions - -Suggestions are a list of possible values for the option. Suggested use-cases -could be for regions/locations, VM sizes, etc... - - -This option is specifically for the Devsy desktop application, suggestions won't -be shown in the CLI app. - - -**If not specified, it defaults to empty and ignored**. - -### Command options - -The command option lets you define a possible value for an option based on a shell -command launched on your machine. Can also reference other variables in the command, e.g. `echo ${MY_OTHER_VAR}-suffix`. For compatibility reasons, this command will be executed in an emulated shell on Windows. - -One example would be to forward ENV variables from your machine to the provider, -for example: +## Examples +Pass a variable from the user's machine: ```yaml - AWS_ACCESS_KEY_ID: - description: The aws access key id - required: false - command: printf "%s" "${AWS_ACCESS_KEY_ID:-}" - AWS_SECRET_ACCESS_KEY: - description: The aws secret access key - required: false - command: printf "%s" "${AWS_SECRET_ACCESS_KEY:-}" +AWS_ACCESS_KEY_ID: + description: The AWS access key ID + command: printf "%s" "${AWS_ACCESS_KEY_ID:-}" ``` -Or running a helper command (defined in the binaries section), and forwarding the result as the option's value: +Run a helper binary and cache the result: ```yaml - AWS_TOKEN: - local: true - hidden: true - cache: 5m - description: "The AWS auth token to use" - command: |- - ${AWS_PROVIDER} token +AWS_TOKEN: + local: true + hidden: true + cache: 5m + description: The AWS auth token to use + command: ${AWS_PROVIDER} token ``` -**If not specified, it defaults to empty and ignored**. - -## Built-In Options +## Built-in options -There are a couple of predefined options from Devsy, that can be used within the default field of another option or in an option command. Some built-in options are only available for `local` options as the `MACHINE_ID` might not be available already. -Predefined options: -- **DEVSY**: Absolute path to the current Devsy CLI binary. Can be used to call a helper function within Devsy or any other Devsy command. Also available on the agent side. -- **DEVSY_OS**: Current Operating system. Can be either: linux, darwin or windows -- **DEVSY_ARCH**: Current operating system architecture. Can be either: amd64 or arm64. -- **MACHINE_ID**: The machine id that should be used. (Only available for local options, commands and machine providers) -- **MACHINE_FOLDER**: The machine folder that can be used to cache information locally. (Only available for local options, commands and machine providers) -- **MACHINE_CONTEXT**: The Devsy context this machine was created in. (Only available for local options, commands and machine providers) -- **MACHINE_PROVIDER**: The provider name that was used to create this machine. (Only available for local options, commands and machine providers) -- **WORKSPACE_ID**: The workspace id that should be used. (Only available for local options, commands and non-machine providers) -- **WORKSPACE_FOLDER**: The workspace folder that can be used to cache information locally. (Only available for local options, commands and non-machine providers) -- **WORKSPACE_CONTEXT**: The Devsy context this workspace was created in. (Only available for local options, commands and non-machine providers) -- **WORKSPACE_PROVIDER**: The provider name that was used to create this workspace. (Only available for local options, commands and non-machine providers) -- **PROVIDER_ID**: The provider name. (Only available for local options, commands and non-machine providers) -- **PROVIDER_CONTEXT**: The provider context. (Only available for local options, commands and non-machine providers) -- **PROVIDER_FOLDER**: The provider folder where the provider config is saved in, can be used to save global information about the provider such as global session tokens etc. (Only available for local options, commands and non-machine providers) +These can be used in `default` and `command`. Some exist only for `local` options, because the machine or workspace does not exist yet when others are resolved. -## Option Groups +- **DEVSY**: absolute path to the Devsy binary. Also available on the agent side. +- **DEVSY_OS**: `linux`, `darwin` or `windows`. +- **DEVSY_ARCH**: `amd64` or `arm64`. +- **MACHINE_ID**, **MACHINE_FOLDER**, **MACHINE_CONTEXT**, **MACHINE_PROVIDER**: the machine's ID, local folder, Devsy context and provider. Machine providers only. +- **WORKSPACE_ID**, **WORKSPACE_FOLDER**, **WORKSPACE_CONTEXT**, **WORKSPACE_PROVIDER**: the same for a workspace. Non-machine providers only. +- **PROVIDER_ID**, **PROVIDER_CONTEXT**, **PROVIDER_FOLDER**: the provider's name, context and config folder. The folder can hold provider-wide data such as session tokens. - -This section is specifically for organizing options in the Devsy Desktop app. -This has no effect on the CLI app. - +## Option groups -You can organize your options in groups, for example: +Option groups organize options in the Desktop app. They have no effect in the CLI. ```yaml optionGroups: - - options: + - name: "AWS options" + options: - AWS_ACCESS_KEY_ID - - AWS_SECRET_ACCESS_KEY - - AWS_AMI - - AWS_DISK_SIZE - AWS_INSTANCE_TYPE - - AWS_VPC_ID - name: "AWS options" defaultVisible: true - - options: + - name: "Agent options" + options: - AGENT_PATH - INACTIVITY_TIMEOUT - - INJECT_DOCKER_CREDENTIALS - - INJECT_GIT_CREDENTIALS - name: "Agent options" - defaultVisible: false ``` -Options are easily grouped by listing them, each group has a `name` and a -`defaultVisible` property, which is **false by default**. -If `defaultVisible` is false, then a user will need to manually expand the option -group in the Desktop App. +Groups are collapsed unless `defaultVisible` is `true`. diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/quickstart.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/quickstart.mdx index 4783b4e48f..cde2657707 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/quickstart.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/quickstart.mdx @@ -3,208 +3,67 @@ title: Quickstart Guide sidebar_label: Quickstart --- -On this page we will cover all the basics to develop a functional provider for Devsy. +A provider is a small program described by a `provider.yaml`. Devsy reads the manifest and calls the commands it defines to create and reach an environment. - -Before starting, it's best if you have already taken a look at [What are providers](../managing-providers/what-are-providers.mdx) -and [How to manage them](../managing-providers/manage-providers.mdx). + +Read [What are providers](../managing-providers/what-are-providers.mdx) and [Add a Devsy Provider](../managing-providers/manage-providers.mdx) first. - -Another good starting point are the official Devsy providers specified at [Add Provider](../managing-providers/manage-providers.mdx) - +## A minimal provider + +This provider runs workspaces on the local machine: -A very basic provider that reuses local Docker to spin up workspaces would look like this: ```yaml -name: my-first-provider # Required name of the provider -version: v0.0.1 # Required version of the provider -agent: # Devsy Agent options - path: ${DEVSY} # Path to the current Devsy binary +name: my-first-provider # required +version: v0.0.1 # required +agent: + path: ${DEVSY} # path to the current Devsy binary exec: - # Command specifies how to run a command in the environment. - # In this case we want to reuse the local environment, so we just execute the command in a local shell. + # How to run a command in the environment. Here: a local shell. command: |- sh -c "${COMMAND}" ``` -You can save this provider to a file called `provider.yaml` and then add it via: -``` -devsy provider add ./path/to/provider.yaml -``` +Save it as `provider.yaml`, add it, and start a workspace: -Then try to start a new workspace with: ``` +devsy provider add ./provider.yaml devsy workspace up github.com/microsoft/vscode-remote-try-go ``` -## Developing a Devsy provider - -Devsy providers are small CLI programs defined through a `provider.yaml` that Devsy interacts with, in order to bring up the workspace. - -Providers are standalone programs that Devsy will call, parsing a **manifest** -called `provider.yaml` that will instruct Devsy on how to interact with the program. The most important sections of a `provider.yaml` are: -* [exec](#how-devsy-interacts-with-a-provider): Defines what commands Devsy should execute to interact with the environment -* [options](./options.mdx): Defines what Options the user can configure in the provider -* [binaries](./binaries.mdx): Defines what additional helper binaries are required to run the provider -* [agent](./agent.mdx): Defines configuration options for the provider such as drivers, auto-inactivity timeout and credentials injection - -## Provider.yaml - -With the `provider.yaml`, Devsy will know how to call the provider's binary, in order -to perform all the required actions to bring up or down an environment for a workspace. +## Sections of provider.yaml -Following is a minimal example manifest for a provider: +- `name`, `version`: required. `description` and `icon` are optional and shown in the Desktop app. +- [`exec`](#exec): the commands Devsy runs to reach and manage the environment. +- [`options`](./options.mdx): settings the user can configure. Devsy passes them to commands as environment variables. +- [`binaries`](./binaries.mdx): helper binaries Devsy downloads for the provider. +- [`agent`](./agent.mdx): how the agent runs in the environment, including the driver, inactivity timeout and credentials. -```yaml -name: name-of-provider -version: version-number -description: quick description # Optional -icon: https://url-to-icon.com # Shown in the Desktop App -options: - # Options for the provider, Devsy will pass these as - # ENV Variables when calling the provider - OPTION_NAME: - description: "option description" - default: "value" - required: true # or false - AGENT_PATH: - description: The path where to inject the Devsy agent to. - default: /opt/devsy/agent -agent: - path: ${AGENT_PATH} -exec: - command: # Required: a command to execute on the remote machine or container - init: # Optional: a command to init the provider, login to an account or similar - create: # Optional: a command to create the machine - delete: # Optional: a command to delete the machine - start: # Optional: a command to start the machine - stop: # Optional: a command to stop the machine - status: # Optional: a command to get the machine's status -binaries: # Optional binaries Devsy should download for this provider - MY_BINARY: # Will be available as MY_BINARY environment variable in the exec section - ... -``` +## exec -### How Devsy interacts with a provider +Each entry is a POSIX shell script. Only `command` is required. -Devsy uses the `exec` section within the `provider.yaml` to know what commands it needs to execute to interact with the provider environments. -These "commands" are regular POSIX shell scripts that call a helper program or directly interact with the underlying system of the user to manage the environment. +- **command**: runs a command in the environment. Devsy uses it to inject itself and sends all traffic through its standard input and output. `${COMMAND}` is a placeholder Devsy fills in. +- **init**: checks that the options are valid and the provider is ready. Devsy runs it when options change. +- **create**, **delete**: create and delete a machine. Defining `create` makes the provider a machine provider, and `delete` is then expected too. +- **start**, **stop**: start and stop a machine. Machine providers only. +- **status**: prints one of `Running`, `Busy` (wait and check again), `Stopped` or `NotFound`. +- **describe**: prints a text description of the machine. -In the `exec` section of the `provider.yaml`, the following commands are allowed: +A provider without `create` is a non-machine provider and uses only `command` and `init`. -- **command**: The only command that is required for a provider to work, which defines how to run a command in the environment. Devsy will use this command to inject itself into the environment and route all communication through the commands standard output and input. An example for a local development provider would be: `sh -c "${COMMAND}"`. -- **init**: Optional command to check if options are defined correctly and the provider is ready to create environments. For example for the Docker provider, this command checks if Docker is installed and reachable locally. -- **create**: Optional command how to create a machine. If this command is defined, the provider will automatically be treated as a machine provider and Devsy will also expect **delete** to be defined. -- **delete**: Optional command how to delete a machine. Counter command to **create**. -- **start**: Optional command how to start a stopped machine. Only usable for machine providers. -- **stop**: Optional command how to stop a machine. Only usable for machine providers. -- **status**: Optional command how to retrieve the status of a machine. Expects one of the following statuses on standard output: - - Running: Machine is running and ready - - Busy: Machine is doing something and Devsy should wait (e.g. terminating, starting, stopping etc.) - - Stopped: Machine is currently stopped - - NotFound: Machine is not found +On Windows, Devsy runs these scripts in an [emulated shell](https://github.com/mvdan/sh), where tools such as `grep` and `sed` are not available. Move that logic into a helper binary. - -Devsy will execute these commands on Unix systems directly in a POSIX shell, while on Windows in an [emulated shell](https://github.com/mvdan/sh) to provide compatibility. However, not all commands, such as `grep`, `sed` etc. are available there and if needed, such functionality should be transferred to a small helper binary Devsy can download and install through the binaries section. - - -For example, taking the [SSH Provider](https://github.com/devsy-org/devsy-provider-ssh): +Example from the [SSH provider](https://github.com/devsy-org/devsy-provider-ssh): ```yaml exec: init: |- - OUTPUT=$(ssh -oStrictHostKeyChecking=no \ - -p ${PORT} \ - ${EXTRA_FLAGS} \ - "${HOST}" \ - 'sh -c "echo DevsyTest"') - + OUTPUT=$(ssh -oStrictHostKeyChecking=no -p ${PORT} ${EXTRA_FLAGS} "${HOST}" 'sh -c "echo DevsyTest"') if [ "$OUTPUT" != "DevsyTest" ]; then - >&2 echo "Unexpected ssh output." - >&2 echo "Please make sure you have configured the correct SSH host" - >&2 echo "and the following command can be executed on your system:" - >&2 echo ssh -oStrictHostKeyChecking=no -p "${PORT}" "${HOST}" 'sh -c "echo DevsyTest"' + >&2 echo "Unexpected ssh output. Check the SSH host and options." exit 1 fi - command: |- - ssh -oStrictHostKeyChecking=no \ - -p ${PORT} \ - "${EXTRA_FLAGS}" \ - "${HOST}" \ - "${COMMAND}" -``` - -The **init** is used to perform actions in order to verify and validate the options -passed (in this case try a dummy command on the selected host) - -The **command** is used to access the remote environment. `${COMMAND}` will be supplied by Devsy and is a placeholder for the command Devsy will execute. -In case of [Machines providers](../managing-providers/what-are-providers.mdx) this will -usually have to SSH on the VMs created. - -### Non-Machine provider - -For Non-Machine providers that don't want to manage any machine lifecycle, the available commands that can be used are: -- command -- init (optional) - -### Machine provider - -For Machine Providers, you can use all of the commands in order to guarantee a full VMs lifecycle management. - -### Options - -The Options section is a set of OPTION_NAME and values that Devsy will inject in -the environment when calling the provider's commands. - -Head over to the [Options Page](./options.mdx) to know more about how to set them up - -### Agent - -One important part of the lifecycle management of the Devsy's provider's resources is the **Agent**. -The agent is a helper that Devsy will inject into the workspace in order to perform utilities like: - -- auto-shutdown the VM after inactivity -- inject git credentials -- inject docker credentials - -Head over to the [Agent page](./agent.mdx) to know more about the agent setup. - -### Binaries - -Devsy allows you to install additional binaries that help you to create cloud resources or access these. For example, the Google Cloud provider installs its own binary via: -```yaml -... -binaries: - GCLOUD_PROVIDER: - - os: linux - arch: amd64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-linux-amd64 - checksum: 38f92457507563ee56ea40a2ec40196d12ac2bbd50a924d76f55827e96e5f831 - - os: linux - arch: arm64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-linux-arm64 - checksum: 48e8dfa20962f1c3eb1e3da17d57842a0e26155df2b94377bcdf5b8070d7b17e - - os: darwin - arch: amd64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-darwin-amd64 - checksum: 43ee6ecb7855d282a0512ccf6055cce029895f173beb95a8c442f77560d26678 - - os: darwin - arch: arm64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-darwin-arm64 - checksum: c2c2d57c5d48f22814f2393f61fd6a78bdc2cde7eabc3faffd8f35eaceec4422 - - os: windows - arch: amd64 - path: https://github.com/devsy-org/devsy-provider-gcloud/releases/download/v0.0.1-alpha.10/devsy-provider-gcloud-windows-amd64.exe - checksum: 9b81ec48c849f222aaf30f0cb85057d4e6619d1c0f787b27925c8b8adb431a58 -exec: - init: ${GCLOUD_PROVIDER} init - command: ${GCLOUD_PROVIDER} command - create: ${GCLOUD_PROVIDER} create - delete: ${GCLOUD_PROVIDER} delete - start: ${GCLOUD_PROVIDER} start - stop: ${GCLOUD_PROVIDER} stop - status: ${GCLOUD_PROVIDER} status + ssh -oStrictHostKeyChecking=no -p ${PORT} "${EXTRA_FLAGS}" "${HOST}" "${COMMAND}" ``` - -You can find more information on the [Provider binaries](./binaries.mdx) page. diff --git a/sites/docs-devsy-sh/content/docs/developing-providers/runtime-protocol.mdx b/sites/docs-devsy-sh/content/docs/developing-providers/runtime-protocol.mdx index 2075055581..507928f581 100644 --- a/sites/docs-devsy-sh/content/docs/developing-providers/runtime-protocol.mdx +++ b/sites/docs-devsy-sh/content/docs/developing-providers/runtime-protocol.mdx @@ -4,7 +4,7 @@ description: Contract for external runtime driver authors using the Devsy Runtim --- -Providers can select `agent.driver: external` using the [external runtime configuration](./driver). The SDK and Devsy host integration are available; backend extraction and parity testing remain in development. +Providers select this protocol with `agent.driver: external`. See the [external driver](./driver.mdx#external-driver). The canonical [protobuf schema](https://github.com/devsy-org/devsy-runtime-sdk/blob/main/proto/devsy/runtime/v1/runtime.proto) is maintained in the [Devsy Runtime SDK](https://github.com/devsy-org/devsy-runtime-sdk). The module path is `github.com/devsy-org/devsy-runtime-sdk`; the logical plugin name is `devsy-runtime`. HashiCorp application protocol 1 and Info API major 1/minor 1 are separate version checks. Same-major newer minor versions are accepted. Unknown mount/recreate enum values are rejected because they control host behavior. @@ -39,10 +39,6 @@ Logs uses merged binary OutputChunk frames. Output buffering must remain bounded Use canonical gRPC status and attach RuntimeError details for stable categories, actionable messages, optional backend diagnostics, retryability, and structured context. Raw backend diagnostics must be redacted before display. Unknown detail fields remain forward-compatible; callers must not parse messages to classify errors. -The plugin binary is trusted provider code. The host resolves it from checksum-verified `Agent.Binaries`, rather than PATH discovery, and runs it through the runtime supervisor. The magic cookie is not a security boundary. See the [driver guide](./driver) for process ownership and the environment-secret lifetime policy. +The plugin binary is trusted provider code. The host resolves it from checksum-verified `Agent.Binaries`, rather than PATH discovery, and runs it through the runtime supervisor. The magic cookie is not a security boundary. -## Current implementation - -The SDK provides generated Go bindings, the shared plugin handshake, server helpers, and Info validation. Devsy integrates the host through the workspace driver factory, with separate image-backend selection and validation before recreation. Real fake-runtime processes exercise the production supervisor, factory, and workspace runner across image creation, discovery, command streams, logs, stop, and delete. Runtime backend extraction and parity testing are the next stage. - -For SDK development commands and package usage, see the [SDK README](https://github.com/devsy-org/devsy-runtime-sdk#readme). +For SDK usage and development commands, see the [SDK README](https://github.com/devsy-org/devsy-runtime-sdk#readme). diff --git a/sites/docs-devsy-sh/content/docs/fragments/virtualbox-ubuntu-22.04.mdx b/sites/docs-devsy-sh/content/docs/fragments/virtualbox-ubuntu-22.04.mdx index 36bb312677..703dd8c5c2 100644 --- a/sites/docs-devsy-sh/content/docs/fragments/virtualbox-ubuntu-22.04.mdx +++ b/sites/docs-devsy-sh/content/docs/fragments/virtualbox-ubuntu-22.04.mdx @@ -8,9 +8,9 @@ This walkthrough targets an x86-64 host and guest image. Download the official I ### New Ubuntu 22.04 Virtual machine -With Virtualbox running, open the a new Virtual machine dialog. 'machine' > 'new ...' +With Virtualbox running, open the new virtual machine dialog with 'Machine' > 'New...'. -### New Virtual Machine dialog +### New virtual machine dialog #### Step 1 - Virtual Machine Name and Operating System @@ -19,7 +19,7 @@ With Virtualbox running, open the a new Virtual machine dialog. 'machine' > 'new | Name | ubuntu-desktop-22.04 (name used through this example) | | Folder | default value is suitable in most cases | | ISO Image | browse to the path of the downloaded ubuntu 22.04 ISO | -| Skip unnattended installation | true / ticked (this setup sudo group during installation) | +| Skip unattended installation | ticked (the installer then sets up the sudo group) | Select 'Next' @@ -64,26 +64,26 @@ Select Language and Install Ubuntu Select your desired Keyboard layout, select 'Continue'. -#### Step 3 - Update and Other Software +#### Step 4 - Update and Other Software | Input | Suggested Value | |---|---| | Name | ubuntu-desktop-22.04 (name used through this example) | | Normal or Minimal Installation | Minimal Installation | -| Download updates will installing Ubuntu | yes | +| Download updates while installing Ubuntu | yes | | Install third party software for graphics and WI-FI hardware and additional media formats | yes (adds closed source drivers and software that can't be included in Ubuntu). You need to understand the consequences of this option for your personal needs. | -#### Step 4 - Installation Type +#### Step 5 - Installation Type Select 'Erase disk and install Ubuntu', click 'Install Now' -Write the changes to disks?. Select 'Continue' +When asked to write the changes to disks, select 'Continue' -#### Step 5 - Where are you? +#### Step 6 - Where are you? Select your location, click 'Continue' -#### Step 6 - Who are you? +#### Step 7 - Who are you? | Input | Suggested value | |---|---| diff --git a/sites/docs-devsy-sh/content/docs/getting-started/install.mdx b/sites/docs-devsy-sh/content/docs/getting-started/install.mdx index b388814bc1..5a73723fa3 100644 --- a/sites/docs-devsy-sh/content/docs/getting-started/install.mdx +++ b/sites/docs-devsy-sh/content/docs/getting-started/install.mdx @@ -5,12 +5,9 @@ sidebar_label: Install Devsy import { Tab, Tabs } from 'fumadocs-ui/components/tabs'; -Devsy comes in two forms that share the same workflow: +Devsy comes as a desktop app and a CLI. Both do the same things. Use the desktop app if you want a UI and the CLI for scripting. -- **Devsy Desktop** - a guided app for creating and managing workspaces. Start here if you want a UI. -- **Devsy CLI** - the same workflow from a terminal, for automation and scripting. - -Install either one below, then head to the [Quick Start](./quickstart.mdx). +Install one, then follow the [Quick Start](./quickstart.mdx). ## Install Devsy Desktop @@ -26,18 +23,12 @@ Download the build for your platform: For earlier versions, see the [GitHub releases page](https://github.com/devsy-org/devsy/releases). - -The DEB and RPM packages declare their runtime dependencies; the AppImage and Flatpak bundle theirs. Most modern desktop distros run the AppImage as-is (tested on Debian 12+, Ubuntu 22.04+, Fedora 36+, openSUSE Leap 15.3+, Tumbleweed, and Arch). - -If the AppImage fails to launch, install FUSE and the GTK/Electron runtime libraries: - -- Debian/Ubuntu: `sudo apt-get install libfuse2 libgtk-3-0 libnotify4 libnss3 libxss1 libxtst6 xdg-utils libatspi2.0-0` -- Fedora: `sudo dnf install fuse-libs gtk3 libnotify nss libXScrnSaver libXtst xdg-utils at-spi2-core` -- openSUSE: `sudo zypper in libfuse2 gtk3 libnotify4 mozilla-nss libXss1 libXtst6 xdg-utils` + +The DEB and RPM packages declare their dependencies, and the AppImage and Flatpak bundle theirs. If the AppImage does not start, install FUSE 2 (`libfuse2` on Debian and Ubuntu) and try again. -Devsy Desktop needs [WebView 2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/?form=MA13LH). It ships with recent versions of Windows - install it only if the app fails to open. +If the app does not open, install [WebView 2](https://developer.microsoft.com/en-us/microsoft-edge/webview2/?form=MA13LH). Recent versions of Windows include it. ## Install Devsy CLI @@ -48,11 +39,11 @@ On macOS or Linux, the quickest option is the install script: curl -L https://devsy.sh/install.sh | sh ``` -The script detects your OS and CPU architecture, downloads the latest CLI build from [GitHub releases](https://github.com/devsy-org/devsy/releases), verifies its SHA-256 checksum when the release publishes one, and installs `devsy` into `/usr/local/bin` (or `~/.local/bin` when `/usr/local/bin` isn't writable). Re-run it any time to get the latest release. On Windows, use the PowerShell command in the Windows tab below. +The script downloads the latest CLI for your OS and architecture from [GitHub releases](https://github.com/devsy-org/devsy/releases), checks its SHA-256 checksum when the release publishes one, and installs `devsy` into `/usr/local/bin`. If it cannot write there and `sudo` is not available, it installs into `~/.local/bin`. Run it again to update. On Windows, use the PowerShell command in the Windows tab below. Two environment variables customize the script: -- `DEVSY_VERSION` installs a specific release instead of the latest: `curl -L https://devsy.sh/install.sh | DEVSY_VERSION=v1.19.0 sh` +- `DEVSY_VERSION` installs a specific release instead of the latest: `curl -L https://devsy.sh/install.sh | DEVSY_VERSION=vX.Y.Z sh` - `DEVSY_INSTALL_DIR` installs somewhere other than the default: `curl -L https://devsy.sh/install.sh | DEVSY_INSTALL_DIR="$HOME/bin" sh` On macOS or Linux, you can also install with [Homebrew](https://brew.sh): @@ -63,7 +54,7 @@ brew install devsy-org/homebrew-tap/devsy Upgrade later with `brew upgrade devsy`. -To download a binary yourself, run the command for your platform below. You can also install the CLI later from Devsy Desktop. +To download a binary yourself, use the command for your platform below. @@ -106,12 +97,8 @@ curl -L -o devsy "https://github.com/devsy-org/devsy/releases/latest/download/de -Confirm the CLI is on your `PATH`: +Check that the CLI is on your `PATH`: ```bash devsy --version ``` - -## Next step - -Create your first workspace in the [Quick Start](./quickstart.mdx). diff --git a/sites/docs-devsy-sh/content/docs/getting-started/quickstart.mdx b/sites/docs-devsy-sh/content/docs/getting-started/quickstart.mdx index eb1e7de41a..9c35c5896c 100644 --- a/sites/docs-devsy-sh/content/docs/getting-started/quickstart.mdx +++ b/sites/docs-devsy-sh/content/docs/getting-started/quickstart.mdx @@ -5,24 +5,12 @@ sidebar_label: Quick Start import AddProvider from '../fragments/add-provider.mdx' -Go from a fresh install to a running workspace in three steps: add a provider, start a workspace, and open it in your editor. First, [install Devsy](./install.mdx). +Go from a fresh install to a running workspace: add a provider, start a workspace, open it in your editor. First, [install Devsy](./install.mdx). -## Prerequisites - -Devsy connects a workspace to the editor you choose. Some paths run without any local install: - -- **VS Code Browser** (`--ide openvscode`) - opens in your browser, no local install. -- **SSH / Vim / Neovim** (`--ide none`) - no local IDE; you connect over SSH. - -For a local editor, install the one you plan to use: - -- **VS Code** - [download VS Code](https://code.visualstudio.com/download). -- **JetBrains** (IntelliJ, GoLand, PyCharm, WebStorm, RustRover, RubyMine, CLion) - install a [JetBrains IDE](https://www.jetbrains.com/) and [JetBrains Gateway](https://www.jetbrains.com/remote-development/gateway/). +Run `devsy ide list` to see every supported editor. VS Code Browser (`openvscode`) and `none` (SSH only) need nothing installed locally. For any other editor, install it first. JetBrains IDEs also need [JetBrains Gateway](https://www.jetbrains.com/remote-development/gateway/). ## Devsy CLI -Fastest path to a running workspace. Make sure the [Devsy CLI](./install.mdx#install-devsy-cli) is installed. - ### 1. Add a provider A provider decides where workspaces run. Add local Docker: @@ -35,20 +23,13 @@ For other backends, see [Add a Devsy Provider](../managing-providers/manage-prov ### 2. Start a workspace -Point Devsy at a repository and choose how to open it with `--ide`: +Point Devsy at a repository and choose an editor with `--ide`: ``` -# VS Code in the browser -devsy workspace up github.com/microsoft/vscode-remote-try-node --ide openvscode - -# VS Code, locally devsy workspace up github.com/microsoft/vscode-remote-try-node --ide vscode - -# No IDE - connect over SSH -devsy workspace up github.com/microsoft/vscode-remote-try-node --ide none ``` -Devsy builds the dev container and opens your IDE connected to it. If you chose `--ide none`, connect over SSH: +Devsy builds the dev container and opens the editor connected to it. With `--ide none`, connect over SSH: ``` ssh WORKSPACE_NAME.devsy @@ -56,42 +37,20 @@ ssh WORKSPACE_NAME.devsy ## Devsy Desktop -Prefer a UI? Make sure [Devsy Desktop](./install.mdx) is installed. - ### 1. Add a provider ### 2. Start a workspace -Go to **Workspaces** > **+ Create** to open the wizard: - -1. **Provider** - pick an initialized provider. -2. **Source** - enter your repository URL or choose a quickstart template. -3. **IDE** - choose how to open the workspace: - - **VS Code** - opens locally, connected to the dev container. - - **VS Code Browser** - opens in your browser, connected to the dev container. - - **JetBrains** - opens through JetBrains Gateway. - - **None** - connect over SSH (Vim/Neovim or a plain session). -4. **Review** - confirm the configuration. -5. **Launch** - start the workspace. - -The wizard streams logs as the workspace starts. When it's ready, your IDE opens connected to the dev container. +Go to **Workspaces** > **+ Create** and follow the wizard: provider, source (a repository URL or a template), editor, review, launch. When the workspace is ready, the editor opens connected to it. -If you chose a JetBrains IDE, Gateway opens with a prefilled form. Press **Check Connection and Continue** to start the IDE inside the workspace. +For a JetBrains IDE, Gateway opens with a prefilled form. Select **Check Connection and Continue** to start the IDE inside the workspace. -### Connect over SSH - -If you chose **None**, connect once the workspace is running: - -``` -ssh WORKSPACE_NAME.devsy -``` - -For Vim/Neovim, either edit remote files over [Netrw](https://www.vim.org/scripts/script.php?script_id=1075) (`vim scp://WORKSPACE_NAME.devsy/path`) or SSH in and install your config as you would on any new machine. +If you chose **None**, connect over SSH as shown above. -To use environment variables in `devcontainer.json` - for example, to control the container image version - see [Environment variables in devcontainer.json](../developing-in-workspaces/devcontainer-json.mdx#environment-variables-in-devcontainerjson). +To use environment variables in `devcontainer.json`, see [Environment variables in devcontainer.json](../developing-in-workspaces/devcontainer-json.mdx#environment-variables-in-devcontainerjson). diff --git a/sites/docs-devsy-sh/content/docs/getting-started/update.mdx b/sites/docs-devsy-sh/content/docs/getting-started/update.mdx index f6363f563b..3016fa4897 100644 --- a/sites/docs-devsy-sh/content/docs/getting-started/update.mdx +++ b/sites/docs-devsy-sh/content/docs/getting-started/update.mdx @@ -5,9 +5,9 @@ sidebar_label: Update Devsy ## Devsy Desktop -Devsy Desktop checks GitHub for new releases shortly after launch and every few hours while running. When an update is available, it downloads in the background and prompts you to restart. After you restart, Devsy runs the latest version. +Devsy Desktop checks GitHub for new releases while it runs. When one is available it downloads in the background and asks you to restart. -If you installed Devsy from a `.deb` or `.rpm` package, update through your package manager instead: [download the latest package](https://github.com/devsy-org/devsy/releases/latest/) and install it again. +If you installed from a `.deb` or `.rpm` package, [download the latest package](https://github.com/devsy-org/devsy/releases/latest/) and install it again. ## Devsy CLI @@ -17,4 +17,4 @@ If you installed with Homebrew, upgrade with: brew upgrade devsy ``` -Otherwise, re-run the install script (`curl -L https://devsy.sh/install.sh | sh`) or the manual command from [Install Devsy CLI](./install.mdx#install-devsy-cli) to download the latest version. +Otherwise, run the install script again (`curl -L https://devsy.sh/install.sh | sh`) or repeat the manual command from [Install Devsy CLI](./install.mdx#install-devsy-cli). diff --git a/sites/docs-devsy-sh/content/docs/how-it-works/deploying-workspaces.mdx b/sites/docs-devsy-sh/content/docs/how-it-works/deploying-workspaces.mdx index eb0de2f035..a9dba5b8fd 100644 --- a/sites/docs-devsy-sh/content/docs/how-it-works/deploying-workspaces.mdx +++ b/sites/docs-devsy-sh/content/docs/how-it-works/deploying-workspaces.mdx @@ -3,84 +3,59 @@ title: How Devsy Deploys Workspaces sidebar_label: Deploying workspaces --- -Devsy deploys workspaces using the "up" command, when executed Devsy builds a devcontainer, if not already available, then uses the provider to deploy the devcontainer to a workspace. Below is a sequence diagram -of the main stages of the "up" command. +`devsy workspace up` builds the devcontainer if needed and uses the provider to start it.
Devsy Up Sequence
Devsy up - Sequence Diagram
-First Devsy checks if we need to create/start a machine to deploy the devcontainer to. Next we pull the source code and .devcontainer.json source from git or a local file and use this with the local environment -to build the workspace. Building is done by the agent since we need access to build tools such as docker buildx/BuildKit (Docker, Apple, Microsandbox drivers) or the dockerless in-cluster builder (Kubernetes and -other drivers without a local container daemon), i.e. `devsy agent workspace build`. The workspace now contains everything needed, so Devsy sets up a SSH connection to the Devsy agent running alongside the -container's control plane. +1. If the provider uses a machine, Devsy creates or starts it. +2. Devsy pulls the source and the `devcontainer.json` from Git or a local folder. +3. The agent builds the workspace image (see [Building](#building)). +4. The agent starts the devcontainer through the driver, for example the Docker daemon or the Kubernetes API. +5. Devsy starts a daemon that stops the machine or container when it is idle, sets up credentials, and opens your IDE. -The agent receives "devsy agent workspace up" with the workspace spec serialised as workspace-info and uses the driver's control plane (the Kubernetes API for k8s, the docker/podman daemon for the Docker driver, -the local `container` CLI for Apple, its own sandbox client for Microsandbox) to start the devcontainer. Once started Devsy deploys a daemon to monitor activity, optionally sets up any platform access for pro -users then optionally retrieves credentials from the local environment before launching the IDE. Once the IDE has started the deployment process has complete, Devsy's agent daemon will continue to monitor the -workspace to put the machine or container to sleep when not in use. +With `devsy workspace up --from-snapshot `, Devsy restores a [snapshot](../developing-in-workspaces/workspace-snapshots.mdx) and skips the build. -Alternatively, `devsy workspace up --from-snapshot ` skips this build-and-deploy flow entirely: it restores a previously saved [workspace snapshot](../developing-in-workspaces/workspace-snapshots.mdx)'s container -filesystem and volumes directly, so no devcontainer build is needed. +## Machines -## Connecting to machines - -In Devsy, machines are the infrastructure that run your devcontainer. Providers like GCP, AWS, and DigitalOcean are considered "machine" providers because they first set up a virtual machine (VM) to host your container. - -When you start a workspace with Devsy, such as running `devsy workspace up`, Devsy uses a selected provider and starts your devcontainer. -If the provider requires a virtual machine (VM), Devsy determines whether to create one. It uses your local environment's credentials and the corresponding CLI tool (e.g., `aws` for AWS or `az` for Azure) to set up the VM. -Once the VM is running, Devsy connects to it through the provider's secure tunnel. Below are examples of providers and their secure tunnels. +Machine providers, such as AWS, GCP, and DigitalOcean, create a VM to host the container. Devsy uses the CLI tool and credentials on your computer, such as `aws` or `az`, to create it, then connects through the cloud's own tunnel: - AWS: [Instance Connect](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html) -- Google Cloud (GCP): [Cloud IAP (Identity-Aware Proxy)](https://cloud.google.com/security/products/iap) +- Google Cloud: [Cloud IAP](https://cloud.google.com/security/products/iap) - Azure: [Azure Bastion](https://learn.microsoft.com/en-us/azure/bastion/bastion-overview) - -Alternatively, you can use [SSH tunneling](https://www.ssh.com/academy/ssh/tunneling-example) to connect to your machines, if supported by your setup. - +You can use [SSH tunneling](https://www.ssh.com/academy/ssh/tunneling-example) instead, if your setup supports it. -The Devsy agent starts a SSH server using the STDIO of the secure tunnel in order for your local Devsy CLI/UI to forward ports over the SSH connection. Once this is done Devsy starts your local -IDE and connects it to the devcontainer via SSH. +The agent runs an SSH server over the tunnel, so the client can forward ports and connect your IDE.
Devsy Architecture
Devsy - Component Diagram
-## Connecting to Kubernetes +## Kubernetes -Devsy works the same with kubernetes as with Machines, the key difference is the secure tunnel is set up using the kubernetes control plane, so a separate machine-level agent is not necessary -to be run on the kubernetes node. Instead the Kubernetes driver talks to the Kubernetes API directly (pod exec/attach, the same mechanism `kubectl exec` uses under the hood) to start and connect -a workspace using a devcontainer. +Kubernetes works the same way, but the tunnel is the Kubernetes API (pod exec and attach), so nothing extra runs on the node.
Devsy Architecture
Devsy - Container Diagram Kubernetes
-Devsy often has to build workspaces even when an "image" is specified in .devcontainer.json. This is because the devcontainer can contain "features" the cause the Dockerfile to be extended. -When this happens, or simply when "build" is used in .devcontainer.json, Devsy falls back to its "dockerless" builder since the Kubernetes driver has no local container daemon to build with: -the workspace pod's main container runs the dockerless build image, builds your image in userspace (see [Reduce build times with a cache](../tutorials/reduce-build-times-with-cache.mdx) -for more on remote caching), then execs into your devcontainer's own entrypoint in place. While building, if REGISTRY_CACHE has been specified in the context options, the dockerless builder will -download existing build layers from the registry to reduce the overall build time. +## Building -
- Devsy Architecture 2 -
Devsy - Component Diagram Kubernetes Build Process
-
+Devsy reads `devcontainer.json`, adds any features as build stages on the base Dockerfile, and builds an OCI image. Features mean a build is often needed even when the file only names an image. -## Building workspaces - -Devsy provides the ability to build workspaces by taking a devcontainer.json and a Git repository to compile an OCI-compliant image with everything you need to develop -against using local tools. +Where there is a local container daemon, Devsy builds with `docker buildx` or its built-in BuildKit client. Where there is none, as with Kubernetes, it uses the dockerless builder, which builds in the workspace pod without a daemon. You can push the image to a registry to cache it. See [Reduce build times with a cache](../tutorials/reduce-build-times-with-cache.mdx).
Devsy Architecture
Devsy - Container Diagram
-It does this by parsing the devcontainer.json, extracting the "features" and appending them as build stages to the base Dockerfile. The container is then built, depending on the driver -this could be docker buildx or Devsy's internal BuildKit client (Docker, Apple, and Microsandbox drivers), or the dockerless in-cluster builder (Kubernetes and other drivers without a local -container daemon), and deployed with the configuration defined by your context. Optionally once the container is built, it can be pushed to a registry to cache for -other developers or in case you rebuild your workspace later. See [Reduce build times with a cache](../tutorials/reduce-build-times-with-cache.mdx). +
+ Devsy Architecture 2 +
Devsy - Component Diagram Kubernetes Build Process
+
diff --git a/sites/docs-devsy-sh/content/docs/how-it-works/overview.mdx b/sites/docs-devsy-sh/content/docs/how-it-works/overview.mdx index a46c9a5e1e..a07407a8d4 100644 --- a/sites/docs-devsy-sh/content/docs/how-it-works/overview.mdx +++ b/sites/docs-devsy-sh/content/docs/how-it-works/overview.mdx @@ -3,26 +3,17 @@ title: How it works sidebar_label: Overview --- -Devsy provisions workspaces on any infrastructure. It wraps the CLI tools you already use - `docker`, `gcloud`, and others - to deploy your development environment and run the dev container, or talks to a provider's API directly (for example, the Kubernetes driver uses the Kubernetes API rather than shelling out to `kubectl`). When creating a workspace, Devsy deploys an agent to both the host machine and the container to handle port forwarding, credential forwarding, and log streaming. The agent acts as a control plane across your development environment. - -Devsy uses a client-agent architecture. The client deploys its own agent, which hosts a gRPC server and an SSH server. This resembles a browser-server architecture where the front end is delivered to a remote host. Two practical wins: - -- No version conflict between client and server - you only install the client. -- No infrastructure to manage. - -For easier debugging, Devsy pipes the agent's STDIO to your local shell so you can see what's happening locally and inside the container. - -Below is a high level overview of how Devsy uses your local environment, a source repo and a devcontainer to deploy your workspace to the cloud. +Devsy has a client and an agent. The client is the CLI or desktop app on your machine. When you create a workspace, the client installs its own agent on the host and inside the container, so you only ever install the client. The agent forwards ports, forwards credentials, and streams logs, and it runs an SSH server that your IDE connects to.
Devsy Architecture
Devsy - Component Diagram
-Devsy connects to the workspace through a vendor-specific channel called the **tunnel**. When you run `devsy workspace up`, Devsy picks a provider based on your context and starts your devcontainer. Machine providers create a VM first if needed. Once the devcontainer is running, Devsy deploys the agent into it. +When you run `devsy workspace up`, Devsy picks a provider, starts the devcontainer, and deploys the agent into it. Machine providers create a VM first if needed. Providers wrap the tools you already use, such as `docker` or `gcloud`, or call an API directly, as the Kubernetes driver does. -The tunnel's transport depends on the provider - AWS uses Instance Connect, Kubernetes uses the Kubernetes API's exec/attach mechanism, and so on. The Devsy agent starts an SSH server over the tunnel's STDIO so the local CLI/UI can forward ports. Devsy then opens your local IDE and connects it to the devcontainer over SSH. +The client reaches the agent through a **tunnel**, and the transport depends on the provider. AWS uses Instance Connect and Kubernetes uses pod exec. The agent runs an SSH server over the tunnel, and Devsy opens your IDE over that SSH connection. Port forwarding works only while an IDE or SSH session is open. -Port forwarding requires an active IDE or SSH session - Devsy needs the agent's SSH server, which only runs while one of those connections is open. +To skip the build, create a workspace from a saved [snapshot](../developing-in-workspaces/workspace-snapshots.mdx) with `devsy workspace up --from-snapshot`. -Instead of building from a devcontainer each time, you can also create a workspace from a previously saved [workspace snapshot](../developing-in-workspaces/workspace-snapshots.mdx) with `devsy workspace up --from-snapshot`, which restores the container filesystem and volumes directly and skips the build step entirely. +For what happens during `up`, see [How Devsy deploys workspaces](./deploying-workspaces.mdx). diff --git a/sites/docs-devsy-sh/content/docs/managing-machines/machine-diagnostics.mdx b/sites/docs-devsy-sh/content/docs/managing-machines/machine-diagnostics.mdx index ffcea2a4d4..8e7f17029c 100644 --- a/sites/docs-devsy-sh/content/docs/managing-machines/machine-diagnostics.mdx +++ b/sites/docs-devsy-sh/content/docs/managing-machines/machine-diagnostics.mdx @@ -3,100 +3,41 @@ title: Machine Diagnostics sidebar_label: Machine Diagnostics --- -Devsy can report the health and recent activity of the inactivity daemon that -runs on a machine. This is useful when a workspace did not stop as expected or -when a machine's automatic shutdown needs investigation. +Use diagnostics when a machine did not stop when you expected. They report on the inactivity daemon that runs on the machine. ```sh devsy machine diagnostics ``` -The command reports the provider's machine state separately from the Devsy -daemon state, its most recent patrol, and the configured workspaces. Use JSON -when integrating diagnostics with another tool: +The output separates the provider's machine state from the daemon's state, and lists the last patrol and each workspace. Add `--result-format json` for scripts. -```sh -devsy machine diagnostics --result-format json -``` - -The plain-text workspace table shows the machine shutdown state for every -workspace and identifies the current shutdown candidate. Devsy runs a -machine-level inactivity action only when every discovered workspace is idle -and none is busy, invalid, or configured without auto-stop. The candidate time -is therefore an eligibility point, not a promise that a machine will stop at -that exact second. - -## Recent diagnostic events +## When a machine stops -Use `machine logs` to show the same structured diagnostic events in a compact -log-style view: - -```sh -devsy machine logs -``` +The daemon stops a machine only when every workspace on it is idle. A workspace that is busy, invalid, or has auto-stop turned off blocks the stop. An inactivity timeout must be a positive duration such as `30m`. -Use `devsy machine logs --follow` to poll for new events every -five seconds until interrupted. Collection has a 30-second timeout and resumes -from the remote cursor, reporting session resets and retention gaps. With -`--result-format json`, each poll writes one JSON response on its own line. -Delivery depends on connectivity and remote retention; this is not an instant -push stream. Desktop refreshes diagnostics every 30 seconds while the machine -detail page is visible and the machine is running, preserving the last known -snapshot through collection failures. +The shutdown candidate shown for a workspace is when it becomes eligible, not a scheduled stop time. New activity moves it, and other workspaces can still block the machine. -Events cover daemon starts and stops, workspace discovery, inactivity deadlines, -and shutdown outcomes. They are not an SSH shell, journald output, Docker logs, -or provider control-plane logs. +## Fields -Diagnostic events are redacted before being written on the machine and retained -within a fixed storage limit. Older events can therefore be rotated; the CLI -and Desktop indicate when an event history gap is detected. - -If a machine is stopped, Devsy does not start it merely to collect diagnostics. -Desktop keeps the last successfully collected snapshot and indicates that it is -historic until the machine is running again. - -## Interpreting the snapshot - -Provider state, daemon health, and snapshot freshness answer different questions: - -| Field | What it tells you | +| Field | Meaning | | --- | --- | -| Provider state | The provider's most recently reported machine state. | -| Daemon health | Whether the daemon's most recently recorded operation succeeded. | -| Snapshot freshness | Whether the remote daemon updated its snapshot recently; not proof of current connectivity. | -| Last patrol | When the daemon last evaluated workspace inactivity. Startup alone does not count as a patrol. | -| Last daemon error | The most recent recorded failure in this daemon session, retained after recovery. Its timestamp distinguishes it from a current failure. | -| Shutdown candidate | All discovered workspace checks permit an inactivity action. Provider state still determines whether the machine actually stopped. | +| Provider state | The last machine state the provider reported. | +| Daemon health | Whether the daemon's last operation succeeded. | +| Snapshot freshness | Whether the daemon updated its snapshot recently. It does not prove the machine is reachable now. | +| Last patrol | When the daemon last checked workspace inactivity. | +| Last daemon error | The latest failure in this daemon session. It stays after recovery, so check its timestamp. | +| Shutdown candidate | Every workspace check allows a stop. The provider state shows whether the machine actually stopped. | -A busy workspace, disabled auto-stop, unavailable workspace state, or invalid -timeout blocks automatic shutdown. An inactivity timeout must be a positive -duration, such as `30m`. An active workspace shows its deadline, but that time -is not a promise: subsequent activity can move it, and other workspaces can -still block the machine action. +## Events -## Event meanings and troubleshooting +```sh +devsy machine logs +``` -Event identifiers remain stable for integrations. Routine lifecycle transitions -use `info`; an invalid workspace configuration uses `warn`; patrol and shutdown -command failures use `error`. Workspace discovery/removal means the daemon found -or lost configuration on disk, not that a provider created or deleted a machine. +This shows recent daemon events: starts and stops, workspace discovery, inactivity deadlines, and shutdown results. Add `--follow` to keep polling for new ones. These are diagnostic events only, not shell, Docker, or provider logs. Older events are rotated out, and the output tells you when it detects a gap. -`shutdown.started` records an attempt. `shutdown.succeeded` means the configured -command returned successfully, not that the provider confirmed shutdown. -`shutdown.failed` records a failed command and makes the snapshot degraded. -An abrupt shutdown may prevent a final event from being written; absence of a -completion event does not prove failure. Repeated failures can represent retries -on later patrols. +`shutdown.succeeded` means the stop command returned successfully, not that the provider confirmed the machine stopped. A missing completion event does not prove failure, because an abrupt shutdown can prevent it from being written. -If diagnostics are stale or unavailable, check the provider state and connection -first. For permission errors, verify the installed daemon reader ownership. For -invalid configuration, correct the workspace settings before expecting auto-stop. -For a command failure, inspect the event's error code and the daemon's operator -logs; user-facing events deliberately avoid raw command output and secrets. +Devsy does not start a stopped machine to collect diagnostics. It only collects while you ask for it, through the CLI or an open machine page in the desktop app, which keeps the last snapshot for a stopped machine. -The host does not collect every machine continuously in the background. CLI -follow and the visible Desktop machine page collect on demand. Remote retention -is bounded, and Desktop keeps up to 2,000 collected events per machine and -context. Gaps and session resets are possible; these views are diagnostic aids, -not a durable audit log or an exactly-once event delivery system. +If diagnostics are stale or unavailable, check the provider state and connection first. diff --git a/sites/docs-devsy-sh/content/docs/managing-machines/manage-machines.mdx b/sites/docs-devsy-sh/content/docs/managing-machines/manage-machines.mdx index a7d2728b07..2c0540b382 100644 --- a/sites/docs-devsy-sh/content/docs/managing-machines/manage-machines.mdx +++ b/sites/docs-devsy-sh/content/docs/managing-machines/manage-machines.mdx @@ -3,100 +3,39 @@ title: Manage Machines sidebar_label: Manage Machines --- -## Create a machine +A machine is a server created by a provider. See [What are machines](./what-are-machines.mdx). Run `devsy machine --help` for every command. -Create a new machine with: - -```sh -devsy machine create --provider -``` - -List all machines: +## Create and list ```sh +devsy machine create --provider devsy machine list ``` -Example output: - -``` - NAME | PROVIDER | AGE --------+----------+------ - | aws | 21s -``` - -Check the state of a machine: +## Check and inspect ```sh -devsy machine status +devsy machine status +devsy machine describe +devsy machine inspect ``` -Example output: - -``` -08:48:58 info Machine '' is 'Running' -``` +`describe` prints the provider's own summary. `inspect` prints the machine configuration as JSON, with sensitive options redacted and hidden options left out. -## SSH into a machine - -Open an SSH session directly to the machine: - -```sh -devsy machine ssh -``` - -## Describe a machine - -Retrieve the provider-generated description of a machine (the same text-based summary the provider itself reports): +## Connect ```sh -devsy machine describe +devsy machine ssh ``` -## Inspect a machine - -Print the machine's configuration as JSON, including its provider and provider options. Sensitive options are redacted and hidden options are omitted: - -```sh -devsy machine inspect -``` - -## Stop a machine - -Stop a machine with: - -```sh -devsy machine stop -``` - -Check the status afterwards: - -```sh -devsy machine status -``` - -Example output: - -``` -08:58:58 info Machine '' is 'Stopped, you can start it via 'devsy machine start '' -``` - -## Start a machine - -Restart a stopped machine with: - -```sh -devsy machine start -``` - -## Delete a machine - -Delete a machine with: +## Stop, start, delete ```sh -devsy machine delete +devsy machine stop +devsy machine start +devsy machine delete ``` -This is non-reversible. All workspace containers and data on the machine are lost. +Deleting a machine cannot be undone. All workspace containers and data on it are lost. diff --git a/sites/docs-devsy-sh/content/docs/managing-machines/what-are-machines.mdx b/sites/docs-devsy-sh/content/docs/managing-machines/what-are-machines.mdx index 777c9e097e..e6e1bd5978 100644 --- a/sites/docs-devsy-sh/content/docs/managing-machines/what-are-machines.mdx +++ b/sites/docs-devsy-sh/content/docs/managing-machines/what-are-machines.mdx @@ -3,10 +3,9 @@ title: What are Machines? sidebar_label: What are Machines? --- -A [Machine Provider](../managing-providers/what-are-providers.mdx) is responsible for provisioning machines to host your workspace. -For cloud providers, these machines are typically virtual machines (VMs). Devsy manages the lifecycle of these machines, including creation and deletion of a workspace. +A machine is the VM a [machine provider](../managing-providers/what-are-providers.mdx) creates to host your workspace. Devsy manages its lifecycle, including creating and deleting it with the workspace. -You can directly manage all the machines in the various workspaces using: +To work with machines directly, use: ```sh devsy machine diff --git a/sites/docs-devsy-sh/content/docs/managing-providers/manage-providers.mdx b/sites/docs-devsy-sh/content/docs/managing-providers/manage-providers.mdx index 838bb0fa16..2b56b217b6 100644 --- a/sites/docs-devsy-sh/content/docs/managing-providers/manage-providers.mdx +++ b/sites/docs-devsy-sh/content/docs/managing-providers/manage-providers.mdx @@ -3,7 +3,7 @@ title: Manage Providers sidebar_label: Manage Providers --- -Devsy providers include: +Providers you can add: - [Docker (docker)](https://github.com/devsy-org/devsy/tree/main/providers/docker) - [Podman (podman)](https://github.com/devsy-org/devsy/tree/main/providers/podman) @@ -18,376 +18,166 @@ Devsy providers include: - [Azure (azure)](https://github.com/devsy-org/devsy-provider-azure) - [Digital Ocean (digitalocean)](https://github.com/devsy-org/devsy-provider-digitalocean) -Install these providers with the Devsy CLI: +List what is available from the CLI: -``` -devsy provider add docker -``` - -List available providers using the command: - -``` +```sh devsy provider list --available ``` -## Adding a Provider +## Add a provider ### Devsy Desktop -Open the Providers view and click **Add**. The provider wizard has four steps: - -1. **Select** - pick a built-in preset, or enter a GitHub link, `provider.yaml` URL, or local file path in the **Provider Source** field below the presets. -2. **Configure** - fill in provider-specific options (the form is generated from the provider's schema). -3. **Initialize** - Devsy runs the provider init and streams logs. -4. **Done** - review the result. Failures show the underlying error. - -The ProviderSheet (click any provider in the list) exposes edit settings, switch version, update, delete, rename, set as default, and re-initialize. - - - The Desktop Application calls `devsy provider add PROVIDER` under the hood. - - -#### Custom Providers +Open **Providers** and click **Add**. The wizard has four steps: -In the Select step, type one of the following into the **Provider Source** field below the preset grid: +1. **Select.** Pick a preset, or enter a GitHub link, a `provider.yaml` URL, or a local path under **Provider Source**. +2. **Configure.** Fill in the options. The form comes from the provider's schema. +3. **Initialize.** Devsy runs the provider init and streams the logs. +4. **Done.** Review the result. A failure shows the underlying error. -- A GitHub link to the provider's project -- A URL to a `provider.yaml` -- A file path to a `provider.yaml` +Click a provider in the list to edit its settings, switch version, update, re-initialize, rename, set it as default, or delete it. ### Devsy CLI -Install any provider from the list with: - ```sh devsy provider add docker -devsy provider add podman -devsy provider add kubernetes -devsy provider add apple -devsy provider add microsandbox -devsy provider add lima -devsy provider add orbstack -devsy provider add ssh -devsy provider add aws -devsy provider add azure -devsy provider add gcloud -devsy provider add digitalocean ``` - - You can use the `--name` flag to add multiple providers of the same type with - different options, for example `devsy provider add aws --name aws-gpu -o - AWS_INSTANCE_TYPE=p3.8xlarge` - - -#### From GitHub - -You can specify a custom provider, directly from GitHub, by using the format -`my-username/repo`, so for example: +Use `--name` to add the same provider more than once with different options: ```sh -devsy provider add devsy-org/devsy-provider-terraform +devsy provider add aws --name aws-gpu -o AWS_INSTANCE_TYPE=p3.8xlarge ``` -Devsy will search the latest release for a `provider.yaml` and download that automatically. This should work for private GitHub repositories where Devsy will use the local https credentials to connect to the GitHub repository. - -If you want to install the provider from a different release, you can do the following: +**From GitHub.** Devsy downloads the `provider.yaml` from the latest release. It uses your local HTTPS credentials, so private repositories work. Add `@` and a tag for another release. ```sh +devsy provider add devsy-org/devsy-provider-terraform devsy provider add my-org/my-repo@v0.0.1 ``` -#### From Local Path - -If you have locally downloaded providers, you can also add them directly to -Devsy, by pointing to the file path of `provider.yaml` manifest: +**From a local path or URL.** ```sh devsy provider add ../devsy-provider-mock/provider.yaml -``` - -#### From URL - -You can also specify the URL to the `provider.yaml` file, for example: - -```sh devsy provider add https://github.com/devsy-org/devsy-provider-ssh/releases/download/v0.0.3/provider.yaml ``` -## Set Provider Options - -Each provider defines its own options, so they differ from provider to provider. - -### Desktop Options - -To manage options from the app, head over the `Providers` section, and click -`Edit` on the provider you want to configure. - -### CLI Options +## Set provider options -Set options during the `add` or `init` phase: +Each provider has its own options. In the desktop app, open **Providers** and click **Edit** on a provider. With the CLI, set options when you add or initialize: ```sh devsy provider add -o KEY=value -``` - -or - -```sh devsy provider init -o KEY=value ``` -To manage options later, list the current values with: +List the options and their current values: ```sh devsy provider get ``` -An example output for the AWS Provider is: - -``` - NAME | REQUIRED | DESCRIPTION | DEFAULT | VALUE -----------------------------+----------+--------------------------------+-------------------------+-------------------------- -AGENT_PATH | false | The path where to inject the | /var/lib/toolbox/devsy | /var/lib/toolbox/devsy - | | Devsy agent to. | | -AWS_ACCESS_KEY_ID | false | The AWS access key id | | -AWS_AMI | false | The disk image to use. | | -AWS_DISK_SIZE | false | The disk size to use. | 40 | 40 -AWS_INSTANCE_TYPE | false | The machine type to use. | c5.xlarge | c5.xlarge -AWS_REGION | true | The AWS cloud region to create | | us-west-2 - | | the VM in, e.g. us-west-1 | | -AWS_SECRET_ACCESS_KEY | false | The AWS secret access key | | -AWS_VPC_ID | false | The vpc id to use. | | -INACTIVITY_TIMEOUT | false | If defined, will automatically | 10m | 10m - | | stop the VM after the | | - | | inactivity period. | | -INJECT_DOCKER_CREDENTIALS | false | If Devsy should inject docker | true | true - | | credentials into the remote | | - | | host. | | -INJECT_GIT_CREDENTIALS | false | If Devsy should inject git | true | true - | | credentials into the remote | | - | | host. | | -``` - -This table is an overview. Change any option with: - -```sh -devsy provider set --option = -``` - -For example, to change the disk size from 40GB to 120GB: +Change one later: ```sh -devsy provider set aws --option AWS_DISK_SIZE=120 +devsy provider set --option KEY=VALUE ``` -Run `devsy provider get aws` again to confirm - the `VALUE` column for `AWS_DISK_SIZE` now reads `120`. - - -## Docker Provider: Contexts and Daemon Endpoints - -Devsy follows standard Docker CLI context and endpoint semantics when running workspaces with the Docker provider. - -### Context Preservation - -When Devsy configures credentials for Docker, it automatically preserves your existing Docker client configuration (`config.json`) and stored context metadata (`contexts/`). This ensures that non-default Docker contexts-such as those managed by Docker Desktop (`desktop-linux`), OrbStack (`orbstack`), or custom remote endpoints-remain active and accessible during workspace creation and execution. +## Docker provider -### Explicit Context Selection (`DOCKER_CONTEXT`) +Devsy follows the Docker CLI's rules for contexts and daemon endpoints. It keeps your existing Docker `config.json` and contexts, so contexts from Docker Desktop, OrbStack, or a remote endpoint keep working. -You can target a specific Docker context explicitly: +Devsy picks the connection in the same order as the Docker CLI: -- Via provider option: - ```sh - devsy provider set docker -o DOCKER_CONTEXT= - ``` -- Via environment variable: - ```sh - DOCKER_CONTEXT= devsy workspace up - ``` +1. `DOCKER_CONTEXT` +2. `DOCKER_HOST` +3. The active context in `$DOCKER_CONFIG/config.json`, or `~/.docker/config.json` when `DOCKER_CONFIG` is not set +4. The local socket, `unix:///var/run/docker.sock` -When set, `DOCKER_CONTEXT` takes precedence over both `DOCKER_HOST` and the persisted current context set in `config.json`. +Set `DOCKER_CONTEXT` or `DOCKER_HOST` as a provider option or as an environment variable: -### Explicit Daemon Targeting (`DOCKER_HOST`) - -To direct Docker commands directly to a specific socket or remote daemon endpoint without using a context, configure `DOCKER_HOST`: - -- Via provider option: - ```sh - devsy provider set docker -o DOCKER_HOST=ssh://user@docker-host - ``` -- Via environment variable: - ```sh - DOCKER_HOST=ssh://user@docker-host devsy workspace up - ``` +```sh +devsy provider set docker -o DOCKER_CONTEXT= +devsy provider set docker -o DOCKER_HOST=ssh://user@docker-host +``` -For remote TCP daemons, enable mutual TLS authentication by configuring `DOCKER_TLS_VERIFY=1` and pointing `DOCKER_CERT_PATH` to your client certificates. +For a remote TCP daemon with mutual TLS, set `DOCKER_TLS_VERIFY=1` and point `DOCKER_CERT_PATH` at your client certificates. ### Rancher Desktop -Devsy supports Rancher Desktop through the Docker provider when Rancher Desktop uses the **Moby** container engine. It follows the same Docker context semantics described above; Rancher Desktop typically provides its CLI at `~/.rd/bin/docker` and uses the `rancher-desktop` context. On macOS, Devsy automatically checks that CLI location when `docker` is not available on the application `PATH`. - -You can configure both values explicitly: +Rancher Desktop works with the Docker provider when it uses the Moby engine. If you use `containerd`, switch to Moby. On macOS Devsy looks for the CLI at `~/.rd/bin/docker` when `docker` is not on your `PATH`. You can set both values yourself: ```sh devsy provider set docker -o DOCKER_PATH="$HOME/.rd/bin/docker" devsy provider set docker -o DOCKER_CONTEXT=rancher-desktop ``` -For troubleshooting, verify the CLI and context directly, then inspect the Devsy provider configuration: - -```sh -"$HOME/.rd/bin/docker" context ls -"$HOME/.rd/bin/docker" context inspect rancher-desktop -"$HOME/.rd/bin/docker" --context rancher-desktop info -devsy provider get docker -``` - -If Rancher Desktop is configured for `containerd`, switch it to Moby before using Devsy's Docker provider. Rancher Desktop `containerd`/`nerdctl` parity is not yet validated by this release. - -### Precedence - -Devsy resolves the active Docker connection in the same order as the Docker CLI: -1. `DOCKER_CONTEXT` (explicit context selection) -2. `DOCKER_HOST` (explicit daemon endpoint) -3. Persisted active context in `$DOCKER_CONFIG/config.json` when `DOCKER_CONFIG` is set, and `~/.docker/config.json` otherwise (used for context resolution and credential preservation) -4. Default local Unix socket (`unix:///var/run/docker.sock`) - -## Single Machine Provider +## Single machine -By default, Devsy will use a separate machine for each workspace using the same provider, -you can enable `Reuse machine` in a provider in order to use a single machine for all workspaces. - -In **the desktop app** the option is available in the option management interface for the provider -(see section above) - -In **the CLI** you can set this option using: +By default each workspace gets its own machine. To share one machine between all workspaces on a provider, turn on **Reuse machine** in the provider's options in the desktop app, or run: ```sh devsy provider init --single-machine ``` -## Default Provider - -When you add a provider, you can mark it as the **default provider**. Devsy then uses it for any workspace you create without specifying another. +## Default provider -In **the desktop app**, you can set a provider to be default in the option management interface for the provider -(see section above) - -In **the CLI** you can set this option using: +Devsy uses the default provider for workspaces that do not name one. Set it in the provider's options in the desktop app, or run: ```sh devsy provider use ``` -## Updating a Provider's Version or Source +## Update a provider -### List available versions +Show available versions. Add `--prerelease` to include pre-releases and `--no-cache` to skip the version cache. ```sh devsy provider versions ``` -The table shows the published tag, date, and whether it's the currently-installed version. Pass `--prerelease` to include pre-releases and `--no-cache` to bypass the version cache. - -### Re-fetch the current source +Fetch the provider's source again. Without a pinned tag this pulls the latest release. With a pinned tag it fetches that same version. ```sh devsy provider set-source ``` -Re-resolves the provider's existing source. If the source is a registry entry or a GitHub repo without a pinned tag, this pulls the latest release. If the source is already pinned (e.g. `github.com/org/repo@v0.1.0`), it re-fetches that same version - use `--version` to move to a different one. - -### Pin to a specific version +Pin a version, or replace the source: ```sh devsy provider set-source --version v0.2.0 -``` - -Equivalent inline form (works for GitHub-hosted providers): - -```sh -devsy provider set-source github.com/my-org/my-repo@v0.2.0 -``` - -### Point at a different source - -The `set-source` command also replaces the provider's source entirely - registry name, GitHub repo, URL, or local path: - -```sh devsy provider set-source my-org/my-repo devsy provider set-source https://path/to/provider.yaml devsy provider set-source ../path-to/provider.yaml ``` -### Desktop - -Open the Providers sidebar, select a provider, and use the ProviderSheet: - -- **Select version** - pick a tag from the versions dropdown to switch versions. -- **Update** - jump to the latest release. The button surfaces an "Update available" banner when one is detected. -- **Initialize** - re-run provider init (handy after upgrades). - -Existing workspaces continue to use the version they were created with. Rebuild a workspace (`devsy workspace up --recreate`) to pick up the new provider. - -## Removing a Provider - -### Devsy Desktop - -Navigate to the 'Providers' view and click on the trash icon of the provider -you want to remove. +In the desktop app, use the provider's **Select version**, **Update**, and **Initialize** actions. -If a workspace is currently using the provider, you'll be prompted to first -remove that workspace, in order to then remove the provider. +Existing workspaces keep the provider version they were created with. Recreate one with `devsy workspace up --recreate` to pick up the new version. -### Devsy CLI +## Remove a provider -Remove an installed provider with: +In the desktop app, click the trash icon on the provider. If a workspace uses it, Devsy asks you to remove that workspace first. With the CLI: ```sh -devsy provider delete +devsy provider delete ``` - Remember first to delete any workspace related to this provider first, or move - them to another provider, else you'll not be able to interact with the - workspace until you re-install the provider used. +Delete or move the provider's workspaces first. Otherwise you cannot use them until you add the provider again. -## Renaming a Provider - -You can rename a provider using the `devsy provider rename` command. All workspaces and machines using the provider continue to work under the new name. Provider configuration, options, and state are fully preserved. - -### CLI +## Rename a provider -```bash +```sh devsy provider rename ``` -#### Example - -```bash -devsy provider rename my-docker local-docker -``` - -### Constraints - -- The new name must be unique - it cannot match an existing provider. -- Provider names can only contain lowercase letters, numbers, and dashes, up to 32 characters. -- Pro providers (proxy/daemon) cannot be renamed. They are managed by the platform. -- Workspaces bound to the provider must be stopped before renaming. - -### What happens - -- The provider is moved to the new name with all options and settings intact. -- All workspaces and machines associated with the provider are updated to reference the new name. -- If the provider was the default, the default is updated to the new name. -- If any step fails, the entire operation is rolled back to the original state. - -### GUI +Workspaces, machines, options, and the default setting follow the new name. If any step fails, Devsy rolls the rename back. -1. Navigate to the **Providers** section. -2. Select the provider you want to rename. -3. In the provider's configuration page, edit the **Provider Name** field. -4. Click **Update Options** to save. +- The new name must be unique and can use lowercase letters, numbers, and dashes, up to 32 characters. +- Pro providers cannot be renamed. +- Stop the provider's workspaces first. -Devsy will update the provider and all associated workspaces automatically. +In the desktop app, edit **Provider Name** in the provider's configuration and click **Update Options**. diff --git a/sites/docs-devsy-sh/content/docs/managing-providers/what-are-providers.mdx b/sites/docs-devsy-sh/content/docs/managing-providers/what-are-providers.mdx index 0ce149a8d6..66333e52ec 100644 --- a/sites/docs-devsy-sh/content/docs/managing-providers/what-are-providers.mdx +++ b/sites/docs-devsy-sh/content/docs/managing-providers/what-are-providers.mdx @@ -3,24 +3,11 @@ title: What are Providers? sidebar_label: What are Providers? --- -A provider is the CLI program Devsy uses to create, manage, and run workspaces on a given backend. This model is what lets Devsy target any infrastructure - local, cloud, Kubernetes, or remote SSH - without changing how you work. +A provider tells Devsy where and how to run workspaces: your machine, a cloud, Kubernetes, or an SSH host. Each provider is a `provider.yaml` that declares its options, binaries, and commands. -Each provider is defined by a `provider.yaml` that declares the options, configuration, binaries, and commands Devsy needs to create workspaces on that backend. +To use one, see [Manage providers](./manage-providers.mdx). To build one, see [How to develop a provider](../developing-providers/quickstart.mdx). -To get started, see [Manage providers](./manage-providers.mdx). To build your own, see [How to develop a provider](../developing-providers/quickstart.mdx). +## Provider types -## Provider Types - -Devsy supports two kinds of providers: - -### Machine providers - -Machine providers create and manage a VM for the workspace, then run the container on it. They also handle the VM lifecycle - starting, stopping, and deleting it as needed. The AWS provider is one example, using EC2 instances to run the environment. - -### Non-machine providers - -Non-machine providers run the workspace container directly on the target, with no VM to manage. Docker, Podman, Kubernetes, and SSH are examples. - -## Manage Providers - -See [Manage Providers](./manage-providers.mdx) for how to add, configure, update, remove, and rename Devsy providers. +- **Machine providers** create a VM for the workspace, run the container on it, and start, stop, and delete the VM as needed. AWS is an example. +- **Non-machine providers** run the container directly on the target. Docker, Podman, Kubernetes, and SSH are examples. diff --git a/sites/docs-devsy-sh/content/docs/troubleshooting/linux-troubleshooting.mdx b/sites/docs-devsy-sh/content/docs/troubleshooting/linux-troubleshooting.mdx index fba11ec990..0541550692 100644 --- a/sites/docs-devsy-sh/content/docs/troubleshooting/linux-troubleshooting.mdx +++ b/sites/docs-devsy-sh/content/docs/troubleshooting/linux-troubleshooting.mdx @@ -3,133 +3,95 @@ title: Linux Troubleshooting sidebar_label: Linux Troubleshooting --- -This purpose of this page is to outline any known issues with using devsy on Linux and provide known workarounds / fixes. +Known issues and fixes on Linux. -### File permission issues when using a local directory and a remoteUser (or containerUser) +### Files owned by an unknown user after using a local folder -When up'ing a workspace using a local directory, that also specifies a remote container user (via devcontainer.json), the ownership of the directory will change -to the remote user. Since this remote user is in a different user namespace, the ownership will appear as a unknown user. To fix this, simply chown the directory -back to the local user, such as `sudo chown -R $(id -un):$(id -gn) .`. The reason this is necessary is by default, when a new user is created by the container runtime, -such as docker, all files from the host file system will be owned by root during the overlay. For your dev environment to be useful remotely, Devsy needs to -chown the workspace to the remote user. Once the workspace has stopped, you need to change the ownership back. In general local direcotories are typically used -for development, once the devcontainer is working it is better to push the workspace to a git repo and use this. - -### Using FISH shell - -Custom configurations in config.fish file run every time a fish -c command is called, so this processes somewhat get on the way of devsy agent workspace up. - -The solution is to move the customizations inside the if status is-interactive case. - -From this +When you start a workspace from a local folder and `devcontainer.json` sets `remoteUser` or `containerUser`, Devsy changes the folder's ownership to that user so the container can write to it. On the host the owner then shows as an unknown user. After the workspace stops, restore it: +```sh +sudo chown -R $(id -un):$(id -gn) . ``` -if status is-interactive - # Commands to run in interactive sessions can go here -end -eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" -# customizations -``` +Local folders suit early work. Once the devcontainer works, push it to a Git repository and use that instead. + +### Fish shell -to this +Anything in `config.fish` runs on every `fish -c` call, which can interfere with `devsy agent workspace up`. Move your customizations inside the `if status is-interactive` block: ``` if status is-interactive - # Commands to run in interactive sessions can go here eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" - # customizations end ``` -### Using SELinux +### SELinux -If you are running SELinux and try to start a workspace with a mounted volume, you may recieve a "Permission Denied" even if the ownership of the files are correct. To resolve -append `:Z` to your volume definitions, like so +With SELinux, a mounted volume can fail with "Permission denied" even when ownership is correct. Add `:Z` to the volume: -``` +```json { - // some fields - "workspaceMount": "", "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}", "runArgs": [ - // other args "--volume=${localWorkspaceFolder}:/workspaces/${localWorkspaceFolderBasename}:Z" ] } ``` -### ENAMETOOLONG error when opening a workspace in vscode +### `ENAMETOOLONG` when opening a workspace in VS Code -There is a [known issue](https://github.com/devsy-org/devsy/issues/1045) where some linux distros use a large PATH to find SSH and causes the connection string to be too long. The workaround is to specify -the SSH binary explicitly in vscode. +Some distributions have a very long `PATH`, which makes the SSH connection string too long. Set the SSH binary explicitly in VS Code. See [issue #1045](https://github.com/devsy-org/devsy/issues/1045). -### Docker socket permission denied +### Docker permission denied or daemon unreachable -If `devsy workspace up` fails with a permission denied error connecting to `docker.sock`, your user is not a member of the `docker` group. Add yourself and re-login: +If `devsy workspace up` fails with a permission error on `docker.sock`, add your user to the `docker` group and log in again: -```bash +```sh sudo usermod -aG docker $USER ``` -If Devsy reports that the Docker daemon is unreachable, start the daemon: +If the daemon is not running, start it: -```bash +```sh sudo systemctl start docker ``` -These failures surface as `code: "UNKNOWN"` with the underlying OS/daemon error text preserved in `message` - see the [Structured CLI errors](./troubleshooting.mdx) reference for details. - ### Podman -#### Rootless socket path +#### Rootless socket -Rootless Podman places its socket at `$XDG_RUNTIME_DIR/podman/podman.sock`. If Devsy cannot connect, it will fail with a "connection refused" or "no such file" style error against that socket path (surfaced as `code: "UNKNOWN"` with the real error text in `message`). Either start the user socket with `systemctl --user start podman.socket`, or set `PODMAN_HOST` explicitly: +Rootless Podman uses the socket `$XDG_RUNTIME_DIR/podman/podman.sock`. If Devsy cannot connect, start the user socket: -```bash -devsy provider set podman --option PODMAN_HOST=unix:///run/user/$(id -u)/podman/podman.sock +```sh +systemctl --user start podman.socket ``` -#### `podman compose` vs `docker-compose` - -`podman compose` is not a built-in implementation - Podman looks for an externally installed Compose provider (`podman-compose`, or a standalone `docker-compose` binary) and delegates to it. If your `devcontainer.json` or workspace scripts call `docker-compose` directly, they will fail once `docker-compose` itself is not installed. Install a provider first, for example: +Or point Devsy at it: -```bash -sudo apt-get install -y podman-compose +```sh +devsy provider set podman --option PODMAN_HOST=unix:///run/user/$(id -u)/podman/podman.sock ``` -`docker-compose-plugin` is not a substitute here - it installs the `docker compose` subcommand of the Docker CLI, not a standalone `docker-compose` executable, and it pulls in Docker as a dependency, which defeats the point of a Docker-free Podman setup. - -Verify a provider is available before relying on `podman compose`: +#### `podman compose` -```bash -podman compose version -which docker-compose podman-compose -``` +`podman compose` hands off to an external provider, either `podman-compose` or a standalone `docker-compose`. Install one: -Once a provider is installed, update references to `docker-compose` to use `podman compose`, or add a shell alias as a stopgap: - -```bash -alias docker-compose='podman compose' +```sh +sudo apt-get install -y podman-compose ``` -`devsy workspace up` handles this automatically - Devsy's compose helper detects Podman via the `ContainerRuntime` interface. The alias is only needed for scripts that run inside the workspace itself. - -#### BuildKit not available +Devsy handles this itself when it starts a workspace. You only need it for scripts that run inside the workspace and call `docker-compose`. -Podman uses buildah internally for `podman build`. Dockerfiles with the `# syntax=docker/dockerfile:1` pragma or BuildKit-specific `RUN --mount` syntax will fail. Remove the syntax pragma and restructure affected `RUN` steps to avoid BuildKit mounts. Most standard Dockerfiles build without changes. +#### BuildKit syntax -#### Volume mount permissions in rootless mode +`podman build` uses buildah, so Dockerfiles with the `# syntax=docker/dockerfile:1` line or `RUN --mount` fail. Remove the syntax line and avoid BuildKit mounts. -Rootless Podman maps UIDs through user namespaces. Files created inside the container appear owned by `nobody` on the host. +#### Volume permissions in rootless mode -**With SELinux**: append `:Z` to volume mounts (see [Using SELinux](#using-selinux) above). +Rootless Podman maps user IDs, so files created in the container can appear owned by `nobody` on the host. With SELinux, use `:Z` as above. Without it, fix ownership: -**Without SELinux**: fix ownership with `podman unshare`: - -```bash +```sh podman unshare chown -R $(id -u):$(id -g) /path/to/volume ``` - -If rootless UID mapping is too restrictive for your workflow, run the container as root using `sudo podman` instead. diff --git a/sites/docs-devsy-sh/content/docs/troubleshooting/troubleshooting.mdx b/sites/docs-devsy-sh/content/docs/troubleshooting/troubleshooting.mdx index 16cc7ba4a5..37743c12d0 100644 --- a/sites/docs-devsy-sh/content/docs/troubleshooting/troubleshooting.mdx +++ b/sites/docs-devsy-sh/content/docs/troubleshooting/troubleshooting.mdx @@ -3,59 +3,56 @@ title: Troubleshooting sidebar_label: Troubleshooting --- -This purpose of this page is to outline any known issues with using devsy and provide known workarounds / fixes. +Known issues and workarounds. For Linux-specific problems, see [Linux troubleshooting](./linux-troubleshooting.mdx). ### Utilities not found in PATH -If Devsy Desktop reports that it cannot find utilities in the PATH, you may need to wrap the call in a shell. Something like - -``` -#! /usr/bin/env sh +If Devsy Desktop cannot find tools such as `docker` in your `PATH`, start it through your shell. On macOS: +```sh +#!/usr/bin/env sh exec $SHELL -c 'exec /Applications/Devsy.app/Contents/MacOS/Devsy' ``` -### Port forwarding not working when NOT using an ide +### Port forwarding does not work without an IDE -Devsy relies on an active SSH session to perform port forwarding to the local host. When running Devsy without an IDE, such as `--ide none`, -an active SSH session needs to be open using `devsy workspace ssh {workspace}` (unless you are specifying forwarded ports using docker compose). +Port forwarding needs an open SSH session. With `--ide none`, keep one open with `devsy workspace ssh WORKSPACE_NAME`. Ports declared in Docker Compose do not need it. -### Structured CLI errors +### Reading CLI errors -Devsy classifies common failures and prints a stable error `code` alongside a `message`. Errors are emitted as a JSON object matching: +Pass `--log-output json` to get errors as JSON with a stable `code` and a `message`. Some errors also include a `hint` and a `context` object. ```json { "code": "UNKNOWN", - "message": "exit status 1: Cannot connect to the Docker daemon" + "message": "exit status 1: something failed" } ``` -This happens automatically whenever Devsy detects a non-interactive/machine consumer (for example, stderr is not a TTY, `--log-output json` or `logfmt` is set, or Devsy Desktop invokes the CLI) - human-readable output is used otherwise. Pass `--log-output json` (or `logfmt`) explicitly to force structured errors, or `--log-output text` to force human-readable ones. - -There are only four stable codes: - | Code | Meaning | |---|---| -| `RATE_LIMITED` | An upstream API rate-limited the request. Wait and retry, or authenticate for a higher limit. | -| `PANIC` | Devsy recovered from an internal panic; the message contains the recovered value. | -| `BUILD_FAILED_RECOVERABLE` | The devcontainer build failed in a way that can be retried (e.g. with `--recovery`). | -| `UNKNOWN` | Devsy could not classify the error into one of the above; the raw underlying error text is preserved verbatim in `message`. | - -In practice, most environment-level failures - such as "Docker is not running," "permission denied connecting to docker.sock," or "Podman user socket unavailable" - do not have a dedicated code today. They surface as `code: "UNKNOWN"` with the original OS or daemon error text preserved in `message`. Re-run with `--debug` to see the full original error chain. +| `RATE_LIMITED` | An upstream API rate-limited the request. Wait and retry, or authenticate. | +| `BUILD_FAILED_RECOVERABLE` | The devcontainer build failed in a way that can be retried, for example with `--recovery`. | +| `docker_daemon_unreachable` | Docker is not running or not reachable. | +| `canceled` | The operation was canceled. | +| `deadline_exceeded` | The operation timed out. | +| `unlock_required`, `unlock_failed` | The secrets store is locked, or unlocking it failed. | +| `secret_backend_unavailable` | The secrets backend could not be reached. | +| `secret_store_corrupt` | The secrets store could not be read. | +| `secret_not_found` | The requested secret does not exist. | +| `PANIC` | Devsy hit an internal error. Please report it. | +| `UNKNOWN` | The error was not classified. The original text is in `message`. | + +Run with `--debug` to see the full error chain. ### Windows: `line 2: $'\r': command not found` -Windows line endings break shell scripts inside the container. Add the following to `.gitattributes`: +Windows line endings break shell scripts inside the container. Add this to `.gitattributes`: ``` *.sh eol=lf ``` -### NeoVim: `$TERM` issues over SSH - -NeoVim can misbehave when `$TERM` isn't set correctly over the SSH provider. A workaround is documented in [issue #1187](https://github.com/devsy-org/devsy/issues/1187). - -### VS Code Browser workspace fails to open on first create +### Neovim: `$TERM` issues over SSH -Earlier versions of Devsy could race when bootstrapping the workspace metadata file used by the VS Code Browser tunnel, causing the first browser session to fail right after `devsy workspace up --ide openvscode`. This is fixed - if you previously hit this, re-run `devsy workspace up` on the affected workspace. When Devsy exits because the workspace could not be located, it returns exit code `75`, which parent processes (including Devsy Desktop) treat as a transient signal and retry. +See [issue #1187](https://github.com/devsy-org/devsy/issues/1187) for a workaround. diff --git a/sites/docs-devsy-sh/content/docs/tutorials/docker-provider-via-wsl.mdx b/sites/docs-devsy-sh/content/docs/tutorials/docker-provider-via-wsl.mdx index 0cf7269866..f0bb3803da 100644 --- a/sites/docs-devsy-sh/content/docs/tutorials/docker-provider-via-wsl.mdx +++ b/sites/docs-devsy-sh/content/docs/tutorials/docker-provider-via-wsl.mdx @@ -3,50 +3,24 @@ title: Docker provider via WSL sidebar_label: Docker provider via WSL --- -## Purpose +This tutorial runs a Docker engine inside WSL2 and connects Devsy, running on Windows, to it over SSH. Docker and the project files stay in the WSL filesystem for speed, while Devsy and the editor run on Windows. -This tutorial sets up a Docker engine inside WSL and connects Devsy, running on Windows, to it over SSH. It keeps Docker and the project files in the WSL filesystem for volume performance while running Devsy and the editor on Windows. - - -## Installing Docker in WSL +## Install Docker in WSL ### Enable WSL2 -Run these commands in **PowerShell as Administrator**. - -You can skip this step if WSL2 is already installed. - -On a recent Windows build, the single command below is the simplest path. It enables the required Windows features, downloads the WSL kernel, sets WSL2 as the default version, and installs a default Linux distribution: +In PowerShell as Administrator, skip this step if WSL2 is already installed: ```powershell wsl --install ``` -If `wsl --install` is unavailable, or you need to enable the features by hand, enable both the Windows Subsystem for Linux and the Virtual Machine Platform. WSL2 requires both optional features: the Virtual Machine Platform provides the lightweight virtual machine that runs the Linux kernel, and without it WSL falls back to WSL1: - -```powershell -dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart -dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart -``` - -Restart the machine, then set WSL2 as the default version so the distribution installed in Step 2 runs as WSL2 rather than WSL1: - -```powershell -wsl --set-default-version 2 -``` +This enables the required features and installs a default Linux distribution. Without `wsl --install`, enable both the Windows Subsystem for Linux and the Virtual Machine Platform features by hand, restart, and run `wsl --set-default-version 2`. Without the Virtual Machine Platform, WSL falls back to WSL1. -### Install a WSL2 distribution - -If you ran `wsl --install` in Step 1 without naming a distribution, a default Linux distribution is installed and you can skip ahead. To install `Ubuntu-24.04`, run the following and supply the `username` and `password` when prompted: - -```powershell -wsl --install Ubuntu-24.04 -``` - -To open the Ubuntu shell, type `wsl` in PowerShell. +To install a specific distribution, run `wsl --install Ubuntu-24.04` and set a username and password. Open its shell with `wsl`. -Steps 3 and 5 use `systemctl` to start Docker and the SSH server. `systemctl` requires systemd enabled inside WSL. Ubuntu 24.04 installed through `wsl --install` has systemd enabled by default. If `systemctl` is unavailable, enable it by adding the following to `/etc/wsl.conf` inside WSL, then restart WSL (`wsl --shutdown` from PowerShell, followed by `wsl`): +The steps below use `systemctl`, which needs systemd inside WSL. Distributions installed through `wsl --install` enable it by default. If it is missing, add this to `/etc/wsl.conf`, then run `wsl --shutdown` from PowerShell and start `wsl` again: ```ini [boot] @@ -54,55 +28,20 @@ systemd=true ``` -### Install Docker in the WSL distribution +### Install Docker Engine -Run the following inside WSL to install the Docker engine on Ubuntu 24.04. This follows the [official Docker Engine installation for Ubuntu](https://docs.docker.com/engine/install/ubuntu/). +Follow the [official Docker Engine installation for Ubuntu](https://docs.docker.com/engine/install/ubuntu/) inside WSL. Then add your user to the `docker` group and start the services: ```bash -# If your machine is behind a corporate firewall, -# define HTTP_PROXY and HTTPS_PROXY before running the commands below. - -sudo apt-get update -sudo apt-get install ca-certificates curl -sudo install -m 0755 -d /etc/apt/keyrings -sudo -E curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc -sudo chmod a+r /etc/apt/keyrings/docker.asc - -echo \ - "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ - $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ - sudo tee /etc/apt/sources.list.d/docker.list > /dev/null -sudo apt-get update -sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin - sudo usermod -aG docker $USER -sudo systemctl enable --now docker.service -sudo systemctl enable --now containerd.service +sudo systemctl enable --now docker.service containerd.service ``` -### Configure a Docker daemon proxy (optional) +Behind a corporate proxy, also [configure the Docker daemon proxy](https://docs.docker.com/engine/daemon/proxy/). -If your machine is behind a corporate firewall, configure the Docker daemon to use the proxy. Run the following inside WSL: +### Install an SSH server -```bash -sudo mkdir -p /etc/systemd/system/docker.service.d -sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf > /dev/null <` with the username created in Step 2. Run these commands in PowerShell: +Download the Docker CLI from the [Docker static binaries for Windows](https://download.docker.com/win/static/stable/x86_64/), extract it, and add its folder to `PATH`. Then create a context that uses SSH. Replace `` with your WSL username: ```powershell docker context create lin --docker "host=ssh://@localhost" @@ -132,54 +61,36 @@ docker context use lin docker run hello-world ``` -The first connection prompts you to accept the SSH host key. If you did not set up key authentication in Step 5, it prompts for the WSL user's password as well. +The first connection asks you to accept the SSH host key. -## Connect Devsy to Docker in WSL +## Connect Devsy -### Configure the Devsy Docker provider - -Add the built-in Docker provider and point it at the WSL daemon over SSH. Set `DOCKER_HOST` to the same SSH endpoint used in Step 7, and `DOCKER_PATH` to the `docker` binary on `PATH`: +Add the Docker provider and point it at the WSL daemon: ```bash devsy provider add docker -o DOCKER_HOST=ssh://@localhost -o DOCKER_PATH=docker ``` -Replace `` with your WSL username. Confirm the provider is configured: - -```bash -devsy provider get docker -``` - -If the provider is already added, update its options with `devsy provider set` instead: - -```bash -devsy provider set docker -o DOCKER_HOST=ssh://@localhost -o DOCKER_PATH=docker -``` +If the provider already exists, use `devsy provider set docker -o ...` with the same options. Check the result with `devsy provider get docker`. -`DOCKER_HOST` is passed through to the Docker CLI as the `DOCKER_HOST` environment variable, so any value the Docker CLI accepts (here, an `ssh://` endpoint) works the same way as it does for `docker context`. +`DOCKER_HOST` accepts anything the Docker CLI accepts. - -When the Docker daemon runs inside WSL but Devsy runs on Windows, the daemon does not see the Windows filesystem at the same paths Windows does. Devsy detects a non-local `DOCKER_HOST` (an `ssh://` or `tcp://` endpoint, rather than the Docker Desktop engine's local socket) and converts Windows drive paths in mounts to their WSL `/mnt/` representation before passing them to the Docker CLI. - -For example, a project at `C:\Users\me\repo` is mounted as `/mnt/c/Users/me/repo` inside the container, matching the location the WSL Docker daemon can read. Keep project files on a Windows drive and let Devsy translate the path; placing project files directly under `\\wsl.localhost\...` UNC paths is not supported for mounts. +When `DOCKER_HOST` is not a local socket, Devsy converts Windows drive paths in mounts to their WSL form. A project at `C:\Users\me\repo` is mounted as `/mnt/c/Users/me/repo`. Keep project files on a Windows drive. Paths under `\\wsl.localhost\...` are not supported for mounts. -### Connect the editor (SSH) +## Connect your editor -Create the workspace and open it in your editor. Devsy writes an SSH config entry for the workspace and the editor connects through Devsy's built-in SSH proxy: +Create the workspace. Devsy adds an SSH config entry named `.devsy`: ```bash devsy up ``` -In VS Code / VSCodium with the [Open Remote - SSH](https://marketplace.visualstudio.com/items?itemName=jeanp413.open-remote-ssh) extension, select **Open Folder in Remote...** and choose the host matching `.devsy` from your SSH config. Devsy tunnels the editor's SSH session through the WSL Docker daemon into the devcontainer, so no manual SSH jump host configuration is required. +In VS Code or VSCodium with the [Open Remote - SSH](https://marketplace.visualstudio.com/items?itemName=jeanp413.open-remote-ssh) extension, choose **Open Folder in Remote...** and select that host. Devsy tunnels the session into the dev container, so no jump host setup is needed. - - -The Devsy tunnel reuses your local SSH keys and SSH agent. If you set up key authentication in Step 5, the same key works for the editor connection. If you see `write EPIPE` in the editor's remote-SSH log, run `devsy up` with `DEVSY_DEBUG=true` so the structured tunnel logs are surfaced - the underlying cause (for example the WSL SSH server not running, or the host key not yet trusted) is otherwise hidden behind the editor's generic pipe error. - +The tunnel reuses your local SSH keys and agent. If the editor log shows `write EPIPE`, run `devsy up` with `DEVSY_DEBUG=true`. The real cause, such as the WSL SSH server not running or an untrusted host key, is otherwise hidden behind that generic error. ## Next steps -With the provider configured, you can create a workspace that runs on the Docker daemon in WSL. Try any of the examples in [Create a Workspace](../developing-in-workspaces/create-a-workspace.mdx). +See [Create a Workspace](../developing-in-workspaces/create-a-workspace.mdx). diff --git a/sites/docs-devsy-sh/content/docs/tutorials/minikube-vscode-browser.mdx b/sites/docs-devsy-sh/content/docs/tutorials/minikube-vscode-browser.mdx index 2880dfc955..daea2b7623 100644 --- a/sites/docs-devsy-sh/content/docs/tutorials/minikube-vscode-browser.mdx +++ b/sites/docs-devsy-sh/content/docs/tutorials/minikube-vscode-browser.mdx @@ -59,7 +59,7 @@ Now to start minikube from home: ~/minikube-start.sh ``` -Note: you need to start minikube between vm shutdown/reboots +Start minikube again after every VM shutdown or reboot. #### Test your install @@ -77,14 +77,14 @@ service/kubernetes ClusterIP 10.96.0.1 443/TCP 4d14h ## Install Devsy -Using the Devsy install for Linux deb [docs](https://devsy.sh/docs/getting-started/install) +Install Devsy from the Linux DEB package, as described in [Install Devsy](../getting-started/install.mdx). Download the deb install ```sh cd ~/ -wget https://github.com/devsy-org/devsy/releases/latest/download/Devsy_linux_amd64.deb?_gl=1*76i3lz*_ga*MTczNjE4NzI1My4xNjkxNDQ1ODU1*_ga_4RQQZ3WGE9*MTY5MjY4MTU4NS45LjAuMTY5MjY4MTU4Ny41OC4wLjA. -O Devsy_linux_amd64.deb +wget https://github.com/devsy-org/devsy/releases/latest/download/Devsy_linux_amd64.deb sudo dpkg -i Devsy_linux_amd64.deb ``` @@ -134,13 +134,13 @@ A `hostPath` volume must exist inside the Minikube node itself (the VM or contai minikube ssh -- sudo mkdir -p /mnt/data/devsy ``` -Create the persisent volume for the Kubernetes Provider. +Create the persistent volume for the Kubernetes Provider. ```sh kubectl create -f ~/devsys/devsy-pv.yml ``` -Confirm the persisent volume has been created. +Confirm the persistent volume has been created. ```sh kubectl get pv @@ -150,16 +150,16 @@ devsy-pv 1Gi RWO Retain ### Locate your kubeconfig -List the director ~/.kube +List `~/.kube` ```sh ls ~/.kube cache completion.bash.inc config ``` -Within .minikube the config file is the kubeconfig that can be used by Devsy kubernetes provider. +The `config` file in `~/.kube` is the kubeconfig that can be used by Devsy kubernetes provider. -Within the kubernetes provider the kubeconfig path will be +In the Kubernetes provider, the kubeconfig path is ``` /home/dev/.kube/config diff --git a/sites/docs-devsy-sh/content/docs/tutorials/podman-provider-setup.mdx b/sites/docs-devsy-sh/content/docs/tutorials/podman-provider-setup.mdx index 58fc004a2e..ee293c8cfb 100644 --- a/sites/docs-devsy-sh/content/docs/tutorials/podman-provider-setup.mdx +++ b/sites/docs-devsy-sh/content/docs/tutorials/podman-provider-setup.mdx @@ -3,218 +3,137 @@ title: Podman Provider Setup sidebar_label: Podman Provider Setup --- -## Purpose +Podman is a built-in Devsy provider. It runs containers without a background daemon and is OCI-compatible, so most `devcontainer.json` files work unchanged. See [known differences](#known-differences) for the exceptions. -Podman is a first-class provider in Devsy. It runs containers without a background daemon - each container is a direct child of the calling process - which eliminates the single-point-of-failure that a persistent Docker daemon introduces. Podman is OCI-compatible, so most existing `devcontainer.json` configurations work without changes - see [Dockerfile features not supported during image build](#dockerfile-features-not-supported-during-image-build) and [`podman compose` vs `docker-compose`](#podman-compose-vs-docker-compose) below for the documented exceptions and required adjustments. +This page covers installing Podman, adding it as a provider, and starting a workspace. -This tutorial walks through installing Podman on your platform, registering it as a Devsy provider, and starting a workspace. - -## Prerequisites - -Install Podman for your platform before registering it as a Devsy provider. +## Install Podman ### Linux -Install `podman` from your distribution's package manager: +Use your package manager: ```bash -# Debian / Ubuntu -sudo apt-get install -y podman - -# Fedora / RHEL / CentOS -sudo dnf install -y podman - -# Arch Linux -sudo pacman -S podman +sudo apt-get install -y podman # Debian / Ubuntu +sudo dnf install -y podman # Fedora / RHEL / CentOS +sudo pacman -S podman # Arch ``` ### macOS -Install via Homebrew or download [Podman Desktop](https://podman-desktop.io): - ```bash brew install podman podman machine init podman machine start ``` -### Windows - -Podman on Windows runs inside WSL2. Install WSL2 first, then install Podman inside your WSL distro. - -**Step 1 - Enable WSL2.** Run the following in **PowerShell (as Administrator)** and restart when prompted: - -```powershell -wsl --install -``` - -**Step 2 - Install Podman inside WSL.** Open your WSL terminal and run: - -```bash -sudo apt-get update && sudo apt-get install -y podman -``` - -**Step 3 - Start the rootless API socket.** On WSL distros with systemd enabled (Ubuntu 22.04+ on WSL2 supports this by default), enable and start the user socket: +[Podman Desktop](https://podman-desktop.io) also works. -```bash -systemctl --user enable --now podman.socket -``` - -Verify the socket was created before using its path: +### Windows -```bash -systemctl --user status podman.socket -ls -la $XDG_RUNTIME_DIR/podman/podman.sock -``` +Podman runs inside WSL2. -If your WSL distro does not have systemd available, start the API service manually instead. A trailing `&` alone won't survive terminal closure - use `setsid`/`nohup` or a process manager instead. `--time=0` disables the API's own inactivity shutdown timeout: +1. In PowerShell as Administrator, run `wsl --install` and restart when asked. +2. In your WSL terminal, run `sudo apt-get update && sudo apt-get install -y podman`. +3. Start the rootless API socket. If your distro has systemd: -```bash -setsid nohup podman system service --time=0 unix://$XDG_RUNTIME_DIR/podman/podman.sock >/tmp/podman-service.log 2>&1 & -``` + ```bash + systemctl --user enable --now podman.socket + ls -la $XDG_RUNTIME_DIR/podman/podman.sock + ``` -Note the socket path - you will need it for the `PODMAN_HOST` option: + Without systemd, start the service so it survives closing the terminal: -```bash -echo $XDG_RUNTIME_DIR/podman/podman.sock -``` + ```bash + setsid nohup podman system service --time=0 unix://$XDG_RUNTIME_DIR/podman/podman.sock >/tmp/podman-service.log 2>&1 & + ``` -## Adding the Podman Provider +4. Note the socket path. You need it for `PODMAN_HOST` below. -Register the built-in Podman provider with Devsy: +## Add the provider ```bash devsy provider add podman ``` -Devsy registers `podman` as an available provider. Confirm it appears in your provider list: - -```bash -devsy provider list -``` - -## Configuration Options - -The Podman provider exposes four options: +## Options | Option | Default | Description | |--------|---------|-------------| -| `PODMAN_PATH` | `podman` | Path to the `podman` binary. Override when `podman` is not on `PATH` - for example, `/usr/local/bin/podman`. | -| `PODMAN_HOST` | *(unset)* | Podman host socket or TCP address (sets `DOCKER_HOST` internally). Required on Windows to point Devsy at the WSL socket, e.g. `unix:///run/user//podman/podman.sock` (replace `` with `id -u`). | -| `PODMAN_ELEVATION` | `none` | Optionally run `podman` commands through a privilege-elevation helper (`pkexec`, `sudo`, or `doas`) for a **rootful** Podman socket the current user cannot access. Leave as `none` for rootless Podman (the default and recommended setup below) - elevating would target a separate rootful instance instead. `pkexec` requires a local desktop session with a running polkit agent; prefer `sudo` or `doas` on headless/SSH hosts. | -| `INACTIVITY_TIMEOUT` | *(unset)* | Stops the container after the specified idle period. Accepts duration strings such as `10m` or `1h`. | +| `PODMAN_PATH` | `podman` | Path to the `podman` binary, if it is not on `PATH`. | +| `PODMAN_HOST` | unset | Podman socket or TCP address. Required on Windows, for example `unix:///run/user//podman/podman.sock`, where `` is the output of `id -u`. | +| `PODMAN_ELEVATION` | `none` | Run `podman` through `pkexec`, `sudo` or `doas` to reach a rootful socket the current user cannot access. Leave it as `none` for rootless Podman. `pkexec` needs a desktop session with a polkit agent, so use `sudo` or `doas` on headless hosts. | +| `INACTIVITY_TIMEOUT` | unset | Stop the container after this idle time, for example `10m` or `1h`. | -Set options after adding the provider using `--option` flags: +Set options when adding the provider, or later: ```bash +devsy provider add podman -o PODMAN_PATH=/usr/local/bin/podman devsy provider set podman --option PODMAN_PATH=/usr/local/bin/podman -``` - -To see available options before setting them: - -```bash devsy provider get podman ``` -Or pass options inline at add time: - -```bash -devsy provider add podman -o PODMAN_PATH=/usr/local/bin/podman -o INACTIVITY_TIMEOUT=1h -``` - -## Rootless vs Rootful Setup - -Podman can run in two modes: +## Rootless and rootful -| Mode | How it works | When to use | -|------|-------------|-------------| -| **Rootless** (default) | Containers run as your user. User namespaces isolate processes from the host. | Recommended for most development workflows. Reduces the blast radius of a compromised container. | -| **Rootful** | Containers run as root inside a Podman machine. | Required when a container needs to bind-mount paths owned by root, or when certain network configurations (e.g. macvlan) are needed. | +Rootless is the default and the recommended setup. Containers run as your user. Use rootful only when a container must bind-mount root-owned paths or needs network setups such as macvlan. -**macOS / Windows - switching machine mode:** +On macOS and Windows, switch the Podman machine mode: ```bash -# Create a new, separate machine that runs rootful -podman machine init --rootful my-rootful-machine - -# Or switch an existing machine to rootful mode in-place -podman machine set --rootful +podman machine init --rootful my-rootful-machine # a new machine +podman machine set --rootful # change the existing machine podman machine stop && podman machine start ``` -`podman machine init` always creates a new machine - it does not replace or remove any existing rootless machine. `podman machine set --rootful` changes the mode of an existing machine in place. Switching a machine's mode does not delete its images, containers, or volumes; they belong to whichever mode created them and are simply hidden while the machine is running in the other mode. They reappear once you switch back. +Switching mode does not delete images, containers or volumes. They are hidden while the other mode is active and return when you switch back. -**Linux - rootless is the system default.** To run rootful containers, prefix commands with `sudo` or add your user to the `wheel` / `sudo` group and run `podman system service` as root. If Devsy itself needs to reach a rootful socket it can't access directly, set `PODMAN_ELEVATION=sudo` (or `doas`/`pkexec`) instead of switching the whole setup to run as root - see the option description above. +On Linux, to reach a rootful socket without running everything as root, set `PODMAN_ELEVATION` to `sudo` or `doas`. -After switching to rootful mode on macOS or Windows, update the `PODMAN_HOST` option in Devsy to point to the rootful socket. The rootful socket lives inside the Podman machine VM and is not directly reachable from the host - run `podman machine inspect` and read the forwarded socket path from `.ConnectionInfo.PodmanSocket.Path` in the output, then set `PODMAN_HOST` to that path. Leave `PODMAN_ELEVATION` as `none` in this case: on macOS/Windows the rootful socket is reached over the already-authenticated machine connection, not local privilege elevation. +After switching a macOS or Windows machine to rootful, set `PODMAN_HOST` to the rootful socket. Run `podman machine inspect` and read `.ConnectionInfo.PodmanSocket.Path`. Keep `PODMAN_ELEVATION` as `none`, because the machine connection is already authenticated. -## Creating a Workspace with Podman - -Start a workspace using the Podman provider by passing `--provider podman` to `devsy workspace up`: +## Start a workspace ```bash devsy workspace up --provider podman --id my-workspace https://github.com/my-org/my-repo -``` - -Devsy builds the workspace image using `podman build` and starts the container. When the workspace is ready, connect to it: - -```bash devsy workspace ssh my-workspace ``` -A successful `devsy workspace ssh` connection confirms the workspace is running under Podman. To verify the Podman binary inside the workspace: - -```bash -podman --version -``` - -## Troubleshooting Common Issues +## Troubleshooting ### Socket not found or permission denied -Devsy cannot reach the Podman socket. Check that the Podman machine is running: - -```bash -podman machine list -podman machine start # if the machine is stopped -``` - -On Linux, confirm the user socket exists: +Devsy cannot reach the Podman socket. On macOS and Windows, check that the machine is running with `podman machine list`, and start it with `podman machine start`. On Linux, check the user socket: ```bash systemctl --user status podman.socket -ls -la $XDG_RUNTIME_DIR/podman/podman.sock ``` -If it does not exist or is inactive, start it with `systemctl --user enable --now podman.socket`. On systemd-less environments (some WSL distros), run `setsid nohup podman system service --time=0 unix://$XDG_RUNTIME_DIR/podman/podman.sock >/tmp/podman-service.log 2>&1 &` instead - a trailing `&` alone won't survive terminal closure. - -If the socket path differs from the default, set `PODMAN_HOST` to the correct path: +If the socket path is not the default, set it: ```bash devsy provider set podman --option PODMAN_HOST=unix:///run/user/$(id -u)/podman/podman.sock ``` -### Dockerfile features not supported during image build +## Known differences + +### Dockerfile builds -Podman uses Buildah for image builds, not Docker BuildKit. Most Dockerfiles are compatible, but a small number of BuildKit-specific syntax extensions (e.g. `RUN --mount=type=cache` with the `buildkit` frontend) may fail or behave differently. If your workspace image uses BuildKit-only syntax, remove the `# syntax=docker/dockerfile:1` pragma or restructure the affected `RUN` steps. +Podman builds with Buildah, not BuildKit. BuildKit-only syntax, such as `RUN --mount=type=cache` under the `buildkit` frontend, can fail. Remove the `# syntax=docker/dockerfile:1` line or rewrite those steps. -### `podman compose` vs `docker-compose` +### Compose -`podman compose` is not a built-in implementation - Podman delegates to an externally installed Compose provider, either the `podman-compose` Python package or a standalone `docker-compose` binary. Install one before relying on `podman compose`: +`podman compose` hands off to an external provider: the `podman-compose` package or a standalone `docker-compose` binary. Install one: ```bash sudo apt-get install -y podman-compose ``` -`docker-compose-plugin` is not a substitute here - it installs the `docker compose` subcommand of the Docker CLI, not a standalone `docker-compose` executable, and it pulls in Docker as a dependency, which defeats the point of a Docker-free Podman setup. - -Verify a provider is available: +The `docker-compose-plugin` package does not work here. It adds the `docker compose` subcommand to the Docker CLI and pulls in Docker. Check what is available: ```bash podman compose version -which docker-compose podman-compose ``` -Once a provider is installed, `podman compose` is compatible with `docker-compose` v2 syntax for most workloads. Update your `devcontainer.json` or workspace scripts to call `podman compose` instead of `docker-compose` directly. +Use `podman compose` instead of `docker-compose` in your scripts. diff --git a/sites/docs-devsy-sh/content/docs/tutorials/reduce-build-times-with-cache.mdx b/sites/docs-devsy-sh/content/docs/tutorials/reduce-build-times-with-cache.mdx index 153ade5449..447f4b929a 100644 --- a/sites/docs-devsy-sh/content/docs/tutorials/reduce-build-times-with-cache.mdx +++ b/sites/docs-devsy-sh/content/docs/tutorials/reduce-build-times-with-cache.mdx @@ -3,22 +3,19 @@ title: Reduce build times with remote caching sidebar_label: Reduce build times --- -Devsy provides the ability to use a registry as a remote backend cache for your container builds. To enable it perform - -``` -devsy context set -o REGISTRY_CACHE={registry} -``` - -where registry follows the syntax "\{domain\}/\{project\}/\{repo\}", such as gcr.io/my-project/my-dev-env +Devsy can use a container registry as a remote cache for builds. Prebuild once, and everyone who builds after that reuses the cached layers. +## Set up -If using the docker provider, ensure your docker environment has the image snapshotter enabled in your daemon (https://docs.docker.com/engine/storage/containerd/) - -Merge the `containerd-snapshotter` setting into your existing `/etc/docker/daemon.json` (or the platform-equivalent path, e.g. via Docker Desktop's Settings > Docker Engine on macOS/Windows) - do not overwrite the whole file, since it may already contain other settings such as registry mirrors or proxy configuration: +Point Devsy at a registry path, in the form `domain/project/repo`: ``` -cat /etc/docker/daemon.json +devsy context set -o REGISTRY_CACHE=gcr.io/my-project/my-dev-env +``` + +With the Docker provider, the Docker daemon needs the containerd image store. Merge this into your existing `/etc/docker/daemon.json`, or use **Settings > Docker Engine** in Docker Desktop, and keep any other settings already in the file: +```json { "features": { "containerd-snapshotter": true @@ -26,38 +23,30 @@ cat /etc/docker/daemon.json } ``` -Then restart Docker to apply the change: - -``` -sudo systemctl restart docker -``` - -Verify the active storage driver is now `containerd`: +Restart Docker, then check that the storage driver is `containerd`: ``` docker info --format '{{.DriverStatus}}' ``` -**Warning:** switching the storage backend does not delete any existing images or containers, but images/containers stored under the previous backend will not be visible while the new backend is active. If you don't see an image you expect after switching, it likely still exists under the previous storage driver rather than having been removed. + +Switching the storage backend does not delete images or containers, but items stored under the old backend are not visible while the new one is active. + + +## Populate the cache -Then prebuild your image, this will populate the registry cache so that developers that need to build updates can build on top of the existing pre build. +Build the workspace image once to fill the cache: ``` devsy workspace build my-workspace ``` -Now the next time you or anyone in your team needs to build an image, it can pull from the cache. If you've made changes to your environment, then Devsy will detect these changes and are -built on top of the existing image layers. - +Later builds pull from the cache and build only what changed. -#### How does Devsy detect changes? +## How Devsy detects changes -Devsy parses your Dockerfile and .devcontainer.json to detect file paths that can affect your build context. Devsy traverses these files and makes a hash of the file contents to use as the -container's image tag. When you make changes to these files, the hash will change causing a rebuild. Thanks to the remote cache the previous layers will be built so only changes are needed. To -reduce build times it is recommened to follow docker's best practices when writing Dockerfiles. +Devsy reads your Dockerfile and `devcontainer.json`, finds the files that affect the build, and hashes their contents into the image tag. When a file changes, the hash changes and Devsy rebuilds, reusing the cached layers it can. Follow Docker's Dockerfile best practices to keep rebuilds small. -#### Why Kaniko? +## Builds in Kubernetes -When Devsy uses the kubernetes driver and needs to build a devcontainer, but your local environment does not have a container runtime, it builds the container in the cluster. It does so using -Kaniko, Kaniko builds the container in userspace and does not require super user priveleges. This is much more secure than docker in docker, where the docker daemon is either mounted locally on -the container or over a network within the cluster, neither being ideal. +With the Kubernetes driver and no container runtime on your machine, Devsy builds the image in the cluster with Kaniko. Kaniko builds in userspace without root, which avoids the risks of Docker in Docker. diff --git a/sites/docs-devsy-sh/content/docs/what-is-devsy.mdx b/sites/docs-devsy-sh/content/docs/what-is-devsy.mdx index d419d00504..0116109ba4 100644 --- a/sites/docs-devsy-sh/content/docs/what-is-devsy.mdx +++ b/sites/docs-devsy-sh/content/docs/what-is-devsy.mdx @@ -1,28 +1,22 @@ --- title: What is Devsy? sidebar_label: What is Devsy? -description: Devsy runs devcontainer-based developer workspaces as Docker containers, Kubernetes pods, or microVMs on local machines, remote SSH hosts, or public and private clouds. +description: Devsy runs devcontainer-based developer workspaces on your machine, a remote host, Kubernetes, or a cloud. --- -Devsy enables organizations to scale their engineering operations through standardized, trusted development environments. Environments run as containers, Kubernetes pods, or hardware-isolated microVMs, defined by a [devcontainer.json](https://containers.dev/) that lives alongside your source. [Devsy providers](./managing-providers/what-are-providers) provision those environments on a developer's machine, any reachable remote host, or in a public or private cloud, and you can extend Devsy with your own custom providers. +Devsy creates development workspaces from a [devcontainer.json](https://containers.dev/) that lives in your repository. A workspace runs as a container, a Kubernetes pod, or a microVM, and your IDE connects to it.
Animated demo of launching Devsy, connecting to a workspace, and opening it in an IDE
Devsy
-Devsy connects each developer's local IDE to the infrastructure where the work runs. The same workspace can live on a laptop, a cloud machine, or a shared remote host, and Devsy creates and manages every workspace the same way. That consistency lets a team standardize on one environment definition and move between backends without re-learning their tooling. +Where a workspace runs is decided by a [provider](./managing-providers/what-are-providers). Use a provider for your own machine, an SSH host, Kubernetes, or a cloud. You can also [write your own](./developing-providers/quickstart). Every workspace is created and managed the same way regardless of provider. ## Why Devsy? -Devsy implements the open [DevContainer standard](https://containers.dev/), so the environment definition your team commits remains portable across every backend Devsy supports. - -For engineering organizations, Devsy delivers: -* **Standardized environments**: Define a workspace once in `devcontainer.json` and give every engineer the same toolchain, dependencies, and configuration. New hires are productive on day one instead of spending days on setup. -* **Cost efficiency at scale**: Run workspaces on the infrastructure you already pay for, and let Devsy shut down idle machines so you spend only on capacity in use. -* **No vendor lock-in**: Choose the infrastructure that fits each team - local, cloud, Kubernetes, or remote SSH hosts. Switch a workspace's provider with a single command, with no rewrite of your environment definition. -* **Flexible development**: Engineers get the same experience locally and remotely, from quick prototyping on a laptop to heavy builds on a cloud machine. -* **Cross-IDE support**: VS Code and its variants and the full JetBrains suite are supported out of the box; any other editor can connect over SSH. -* **Extensible**: Devsy is open source and extensible. If a provider doesn't exist for your platform, you can build one. -* **Rich feature set**: Prebuilds, inactivity-based shutdown, and Git and Docker credential sync are built in, with more capabilities on the way. -* **Desktop app and CLI**: The desktop application gives engineers a guided way to manage workspaces, while the CLI drives automation and platform integration across your organization. +- **One environment definition.** `devcontainer.json` is the open standard, so the same file works on every provider. +- **Your infrastructure.** Run workspaces on machines you already pay for. Machine providers can stop idle machines with an [inactivity timeout](./developing-in-workspaces/inactivity-timeout). +- **No lock-in.** Move a workspace to another provider without changing its definition. +- **Your editor.** VS Code, the JetBrains IDEs, and any editor that can connect over SSH. +- **Desktop app and CLI.** The desktop app is for everyday use. The CLI is for automation.