{"id":21453615,"url":"https://github.com/queil/rooz","last_synced_at":"2026-04-11T21:20:31.461Z","repository":{"id":107021390,"uuid":"602027932","full_name":"queil/rooz","owner":"queil","description":"Work in containers","archived":false,"fork":false,"pushed_at":"2026-01-29T21:57:12.000Z","size":822,"stargazers_count":3,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-30T05:36:34.272Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/queil.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2023-02-15T10:49:18.000Z","updated_at":"2026-01-24T16:34:15.000Z","dependencies_parsed_at":"2023-12-30T20:28:38.686Z","dependency_job_id":"da7da20e-7140-46db-8188-3c098fdcff55","html_url":"https://github.com/queil/rooz","commit_stats":null,"previous_names":[],"tags_count":156,"template":false,"template_full_name":null,"purl":"pkg:github/queil/rooz","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queil%2Frooz","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queil%2Frooz/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queil%2Frooz/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queil%2Frooz/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/queil","download_url":"https://codeload.github.com/queil/rooz/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/queil%2Frooz/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29333155,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T12:42:24.625Z","status":"ssl_error","status_checked_at":"2026-02-11T12:41:23.344Z","response_time":97,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-23T04:40:17.465Z","updated_at":"2026-04-11T21:20:31.421Z","avatar_url":"https://github.com/queil.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003cimg width=\"180\" src=\"https://github.com/queil/rooz/blob/main/assets/rooz512.webp?raw=true\" alt=\"Rooz\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003erooz\u003c/h1\u003e\n\nRooz is a CLI tool that enables you to work in containers. It is intended for developers and DevOps engineers. Because of that, it comes with a built-in support for git repositories, SSH keys generation, support for git-safe secrets, shared caches, sidecar containers, declarative configuration, and a robust CLI. Rooz is designed to share as little as possible with the host so it can also orchestrate your workspaces on remote Docker/Podman hosts.\n\n## Quick start\n\n### Install\n\n#### MacOs\n\n```sh\ncurl -sSL https://github.com/queil/rooz/releases/latest/download/rooz-aarch64-apple-darwin -o ./rooz \u0026\u0026 chmod +x ./rooz \u0026\u0026 sudo mv ./rooz /usr/local/bin\n```\n\n#### Linux\n\n```sh\ncurl -sSL https://github.com/queil/rooz/releases/latest/download/rooz-x86_64-unknown-linux-gnu -o ./rooz \u0026\u0026 chmod +x ./rooz \u0026\u0026 sudo mv ./rooz /usr/local/bin\n```\n\n### Initialize\n\n:warning: If you intend to use a remote Docker host with rooz please [configure it first](#connecting-to-a-remote-dockerpodman-host)\n\nTo initialize rooz run the following command:\n\n```sh\nrooz system init\n```\n\nThe command creates:\n\n* an SSH key pair (ed25519) intended to use for auth wherever SSH keys can be used (like github.com)\n  \n  The generated key gets stored in a volume and then mounted under `~/.ssh` to all rooz workspace containers.\n\n* an age encryption key pair intended to use for encryption of sensitive config data (i.e. secrets)\n\n  The generated key gets stored in the system config volume.\n\n  :information_source: It's important to back up the generated age identity. Run `rooz system configure` to view it.\n  If the key is lost all the existing config files with encrypted vars won't decrypt and re-encrypting will be required.\n  To init rooz with an existing age identity use the `--age-identity` switch.\n\nYou can regenerate the keys by specifying the `--force` parameter. Please note that the existing keys will be wiped out.\n\n### Configure\n\n:information_source: Read more in the [Configuration](#configuration) section\n\nRooz works best with user's provided custom image(s).\nYou can pass image, shell, and user via cli parameters but it's much more convenient to set it up \nin your host's `~/.bashrc` (or a non-bash equivalent), and only override it via cli when required.\n\n#### Example configuration:\n\n```sh\nexport ROOZ_USER=queil\nexport ROOZ_IMAGE=ghcr.io/queil/image:latest\nexport ROOZ_SHELL=bash\nexport ROOZ_CACHES='~/.local/share/containers/storage/'\n```\n\n### System config\n\nRooz exposes some system config via `rooz system configure`. At present it only allows to specify `.gitconfig` used by rooz for cloning. It can be used e.g. to specify aliases. This feature is new and may be extended in the future. It also contains the age key for secret's encryption/decryption.\n\n## Usage examples\n\n### Create an empty workspace\n\n```sh\nrooz new myworkspace\n```\n\n### Create a workspace from a git repo\n\n```sh\nrooz new -g git@github.com:your/repo myworkspace2\n```\n### \n\n### Enter a previously created workspace\n\n```sh\nrooz enter myworkspace2\n```\n\n### Interactive shell in an anonymous ephemeral workspace\n\n```sh\nrooz tmp --image alpine --shell sh\n```\n\n## Configuration\n\n:information_source: Rooz supports `yaml` as configuration formats.\n\nMost of the settings can be configured via:\n\n* environment variables\n* a config file in the cloned repository (if any)  (`.rooz.yaml`)\n* a config file specified via `--config` (on `rooz new`)\n  :information_source: it can be a local file path or a remote git file like: `git@github.com/my/configs//path/in/repo/config.rooz.yaml`\n* cmd-line parameters\n\nThe configuration file provides the most options: [example](examples/dotnet-nats.rooz.yaml)\n\n### Images\n\n:information_source: the default image is `docker.io/chainguard/git:latest-dev`\n\nThere are a few ways of specifying images:\n* via the `ROOZ_IMAGE` env variable\n* via  the `--image` cmd-line parameter\n* if creating a workspace with a git repository via `.rooz.yaml` in the root of that repository:\n\n  ```yaml\n  image: ghcr.io/queil/image:dotnet\n  shell: bash\n  ```\n\n### User\n\n`rooz` runs as uid `1000` (always - it's hard-coded) so make sure it exists in your image\n(with `rooz_user` as the name - it can be overridden via `ROOZ_USER` or `--user`)\n\n### Shell\n\nThe default shell is `bash` but you can override it via:\n\n* `ROOZ_SHELL` env var\n* `--shell` cmd-line parameter (on `rooz enter`)\n* in `.rooz.yaml` via `shell`\n\n### Caching\n\n`rooz` supports basic path-keyed shared caches. It can be set per-repo like:\n\n```yaml\ncaches: \n- ~/.nuget\n```\n\nAll the repos specifying a cache path will share a container volume mounted at that path enabling cache reuse.\nIt also can be set globally via `ROOZ_CACHES` (comma-separated paths). The global paths get combined with repo-specific paths.\n\n### Port mappings\n\nPort mappings for the work container can be specified via `.rooz.yaml` only:\n\n```yaml\nports:\n- \"80:8080\"\n- \"22:8022\"\n```\n\n## Variables/templating\n\nRooz supports basic variable replacement/templating:\n* [handlebars](https://handlebarsjs.com/guide/) syntax is used\n* variables are declared via `vars`\n* secrets are declared via `secrets`\n* secrets are decrypted before expanding\n* handlebars can be used in the most of the config values but not in YAML keys\n* vars/secrets replacement works within `vars` themselves too. However, only if the var usage is \nbelow the var definition (in the document order).\n* the secret section does not support var/secrets replacement\n\n```yaml\nsecrets:\n  sqlPassword: '----BEGIN AGE ENCRYPTED FILE-----|YWdlLWVuY3J ... truncated'\n\nvars:\n  sqlUser: admin\n  sqlConnectionString: \"uid={{ sqlUser }};pwd={{ sqlPassword }}\"\n\nenv:\n  SQL_CONNECTION_A: \"database=A;{{ sqlConnectionString }}\"\n  SQL_CONNECTION_B: \"database=B;{{ sqlConnectionString }}\"\n\nsidecars:\n  tool:\n    env:\n      SQL_USER: \"{{ sqlUser }}\"\n      SQL_PASSWORD: \"{{ sqlPassword }}\"\n\n```\n\n## Secrets\n\nRooz uses [age](https://github.com/C2SP/C2SP/blob/main/age.md) encryption to safely store\nsensitive data (like API keys) in config files.\n\n### Example\n\nMake sure your rooz has been initiated with `rooz system init`\n\nRun `touch example.yaml` and `rooz config edit example.yaml`. Your default editor should open.\n\nPaste the following config, save \u0026 quit.\n\n```yaml\nsecrets:\n  apiKey: 1744420283158995\n\nenv:\n  API_URL: https://api.rooz.dev/v1\n  API_KEY: \"{{ apiKey }}\"\n\n```\n\nNow `cat example.yaml` and you should see something like the below:\n\n```yaml\nsecrets:\n  apiKey: '----BEGIN AGE ENCRYPTED FILE-----|YWdlLWVuY3J ... truncated'\nenv:\n  API_URL: https://api.rooz.dev/v1\n  API_KEY: \"{{ apiKey }}\"\n\n```\n\nNow, we can create a new workspace like:\n\n```sh\nrooz new secrets-test --config ./example.yaml\n```\n\nAnd enter the container and the `API_KEY` var is value gets decrypted and injected:\n\n```sh\nrooz enter secrets-test\n\n\u003e echo $API_KEY\n1744420283158995\n```\n\n## Sidecars\n\n*It's similar to docker-compose but super simple and limited to bare minimum.*\n\n* `rooz` has a limited support for sidecars (containers running along). It is only available via the config file\n\n  ```yaml\n  sidecars:\n    sql:\n      image: my:sql\n      command:\n      - --some\n      env:\n        TEST: \"true\"\n  \n    tools:\n      image: my:tools\n  \n  ```\n  All containers within a workspace are connected to a workspace-wide network. They can *talk* to each other using sidecar names. In the above examples that would be `sql` and `tools`. Also the usual container ID and IP works too, but it is not as convenient.\n\n* the `enter` command lets you specify `--container` to enter (otherwise it enters the work container).\n\nSupported keywords:\n* `image` - set containers image\n* `env` - set environment variables\n* `command` - override container entrypoint (`ENTRYPOINT` in Dockerfile)\n* `args` - override container entrypoint arguments (`CMD` in Dockerfile)\n* `mounts` - mount automatically-named rw volumes at the specified paths (so they can survive container restarts/deletes). It supports:\n\n```yaml\n  mounts:\n  # simple empty rw volumes\n  - /my_test/data/\n  # config files with a specified content\n  - mount: /etc/tool/\n    files:\n      config.json: |-\n        {\"some\": \"config\"}\n      other.yaml: |-\n        some: config\n```\n\n* `ports` - port bindings in the `\"8080:8080\"` format\n* `work_dir` - set working directory\n* `mount_work` (`bool`) - if true then the work volume is mounted at `/work`\n\n## Other facts\n\n* cloned git repos are under `/work/{repo_name}` where `repo_name` is the default one generated by `git` during cloning.\n* you can enable `rooz` debug logging by setting the `RUST_LOG=rooz` env variable\n\n* if `rooz` misbehaves you can go nuclear and run `rooz system prune` to remove ALL the rooz containers and volumes. You can also remove just the workspaces, (leaving shared caches volumes, and the ssh volume untouched), by: `rooz rm --all --force`\n\n  :warning: `rooz system prune` deletes all your state held with `rooz` so make sure anything important is stored before.\n\n## Known issues\n\n* auto-resizing rooz session to fit the terminal window (if resized) is not implemented. Workaround: exit the session, resize the window to your liking, enter the container.\n\n## Connecting to a remote Docker/Podman host\n\nRooz connects to a local Docker daemon by default. However, it can connect to remote\nhosts via SSH and forward a local unix socket to the remote's Docker/Podman socket.\n\n### Preparation\n\n#### The remote host\n\n* In `~/.bashrc` at the top:\n  \n  * For Docker as root: `export DOCKER_HOST=/var/run/docker.sock`\n  * For rootless Docker: `export DOCKER_HOST=/run/user/1000/docker.sock` (assuming your-user has uid=1000)\n  * For Podman: `export DOCKER_HOST=/run/user/1000/podman/podman.sock` (assuming your-user has uid=1000)\n\n#### The local host\n\nAdd to your `~/.bashrc`:\n\n* `export ROOZ_REMOTE_SSH_URL=ssh://your-user@remote-host`\n* `export DOCKER_HOST=unix:///home/your-user/.rooz/remote.sock`\n\nNow run: `rooz remote`. If any remote containers\nexpose ports, these will be automatically forwarded.\n\n:information_source: To enable VsCode to attach to remote containers also set the below in `settings.json`:\n\n```json\n   \"docker.host\": \"unix:///home/your-user/.rooz/remote.sock\"\n```\n\n## Running with Podman\n\n1. Make sure podman remote socket is enabled:\n\n`podman info` should contain the following YAML:\n\n```yaml\nremoteSocket:\n    exists: true\n    path: /run/user/1000/podman/podman.sock\n```\n\nIf `exists: true` is missing, try this command: `systemctl --user enable --now podman.socket`\n\n2. Make sure you have the podman socket exposed as the `DOCKER_HOST` env var like:\n\n```\nexport DOCKER_HOST=unix:///run/user/1000/podman/podman.sock\n```\n\n3. Use fully-qualified image names or define unqualified-search registries `/etc/containers/registries.conf`\n\n4. When running more complex podman in podman scenarios (like networking) you may need to run rooz with `--privileged` switch\n   [more info](https://www.redhat.com/sysadmin/privileged-flag-container-engines).\n\n## Resources\n\n* [my image I use with rooz](https://github.com/queil/image/blob/main/src/Containerfile)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqueil%2Frooz","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqueil%2Frooz","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqueil%2Frooz/lists"}