{"id":13522492,"url":"https://github.com/robinovitch61/wander","last_synced_at":"2025-10-06T20:19:23.002Z","repository":{"id":37624517,"uuid":"481096696","full_name":"robinovitch61/wander","owner":"robinovitch61","description":"A terminal app/TUI for HashiCorp Nomad","archived":false,"fork":false,"pushed_at":"2024-06-18T23:55:45.000Z","size":65827,"stargazers_count":459,"open_issues_count":4,"forks_count":16,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-31T22:34:25.054Z","etag":null,"topics":["bubbletea","charm","charmbracelet","hacktoberfest","hashicorp","hashicorp-nomad","nomad","terminal","tui","wish"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/robinovitch61.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}},"created_at":"2022-04-13T06:21:28.000Z","updated_at":"2025-03-28T21:46:23.000Z","dependencies_parsed_at":"2023-02-12T14:31:39.980Z","dependency_job_id":"a87e8a43-9163-416f-952b-807978d93f81","html_url":"https://github.com/robinovitch61/wander","commit_stats":null,"previous_names":[],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/robinovitch61/wander","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robinovitch61%2Fwander","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robinovitch61%2Fwander/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robinovitch61%2Fwander/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robinovitch61%2Fwander/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/robinovitch61","download_url":"https://codeload.github.com/robinovitch61/wander/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/robinovitch61%2Fwander/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278672156,"owners_count":26025848,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["bubbletea","charm","charmbracelet","hacktoberfest","hashicorp","hashicorp-nomad","nomad","terminal","tui","wish"],"created_at":"2024-08-01T06:00:47.946Z","updated_at":"2025-10-06T20:19:22.949Z","avatar_url":"https://github.com/robinovitch61.png","language":"Go","funding_links":[],"categories":["Go","User interfaces","\u003ca name=\"system\"\u003e\u003c/a\u003eSystem tools","Infrastructure setup","Table of Contents","Applications"],"sub_categories":["User Interfaces and Dashboards","Cloud and DevOps"],"readme":"# wander\n\n\u003cimg src=\"./img/logo.png\" width=\"35%\"/\u003e\n\u003cp\u003e\n    \u003ca href=\"https://github.com/robinovitch61/wander/releases\"\u003e\u003cimg src=\"https://shields.io/github/v/release/robinovitch61/wander.svg\" alt=\"Latest Release\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://pkg.go.dev/github.com/robinovitch61/wander?tab=doc\"\u003e\u003cimg src=\"https://godoc.org/github.com/golang/gddo?status.svg\" alt=\"GoDoc\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/robinovitch61/wander/actions\"\u003e\u003cimg src=\"https://github.com/robinovitch61/wander/workflows/build/badge.svg\" alt=\"Build Status\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nAn efficient terminal application/TUI for interacting with your [HashiCorp Nomad](https://www.nomadproject.io/) cluster.\n\n- Browse jobs, allocations, and tasks\n- Live tail logs\n- Tail global or targeted events\n- Exec to interact with running tasks\n- Administrative actions (e.g. restart tasks)\n- View resource usage stats (memory, CPU)\n- See full job or allocation specs\n- Save any content to a local file\n\n`wander` is written with tools from [Charm](https://charm.sh/).\n\n[Feature requests and bug reports are welcome](https://github.com/robinovitch61/wander/issues/new/choose).\n\n## Demo\n\n![](./img/wander.gif)\n\n[Screenshots](./img/screenshots#readme)\n\n## Flow Diagram\n![](./img/wander_flow.drawio.png)\n\n## Installation\n\nThe following options are available depending on your platform and tooling:\n\n```shell\n# homebrew\nbrew install robinovitch61/tap/wander\n\n# upgrade using homebrew\nbrew update \u0026\u0026 brew upgrade wander\n\n# nix-shell\n# ensure NUR is accessible (https://github.com/nix-community/NUR)\nnix-shell -p nur.repos.robinovitch61.wander\n\n# nix flakes\n# ensure flake support is enabled (https://nixos.wiki/wiki/Flakes#Enable_flakes_temporarily)\nnix run github:robinovitch61/nur-packages#wander\n\n# arch linux\n# PKGBUILD available at https://aur.archlinux.org/packages/wander\nyay -S wander-bin\n\n# with go (https://go.dev/doc/install)\ngo install github.com/robinovitch61/wander@latest\n\n# windows with winget\nwinget install robinovitch61.wander\n\n# windows with scoop\nscoop bucket add robinovitch61 https://github.com/robinovitch61/scoop-bucket\nscoop install wander\n\n# windows with chocolatey\nchoco install wander\n```\n\nYou can also download [prebuilt releases](https://github.com/robinovitch61/wander/releases) and move the unpacked\nexecutable to somewhere in your `PATH`, e.g. `/usr/local/bin`.\n\n## Usage\n\nRun the app by running `wander` in a terminal. See `wander --help` and config section below for details.\n\n## Configuration\n\n`wander` can be configured in three ways:\n\n1. Command line arguments, visible by running `wander --help`.\n2. Environment variables. These map to the configuration file below (e.g. `nomad_addr` in yaml is the `NOMAD_ADDR`\n   environment variable).\n3. A yaml config file at `$HOME/.wander.yaml`, or a custom config file path passed to the `--config` argument. Complete\n   example below.\n\nPriority in order of highest to lowest is command line arguments, then environment variables, then the config file.\n\nExample yaml file showing all options (copy this into `$HOME/.wander.yaml` and uncomment/edit as desired):\n\n```yaml\n# Nomad address. Default \"http://localhost:4646\"\n#nomad_addr: \"http://localhost:4646\"\n\n# Nomad token\n#nomad_token: \"\"\n\n# Nomad region\n#nomad_region: \"\"\n\n# Nomad namespace. Default \"*\"\n#nomad_namespace: \"*\"\n\n# Nomad http auth, in the form of \"user\" or \"user:pass\"\n#nomad_http_auth: \"\"\n\n# Path to a PEM encoded CA cert file to use to verify the Nomad server SSL certificate\n#nomad_cacert: \"\"\n\n# Path to a directory of PEM encoded CA cert files to verify the Nomad server SSL certificate. If both cacert and capath are specified, cacert is used\n#nomad_capath: \"\"\n\n# Path to a PEM encoded client cert for TLS authentication to the Nomad server. Must also specify client key\n#nomad_client_cert: \"\"\n\n# Path to an unencrypted PEM encoded private key matching the client cert\n#nomad_client_key: \"\"\n\n# The server name to use as the SNI host when connecting via TLS\n#nomad_tls_server_name: \"\"\n\n# If True, do not verify TLS certificates. Default False\n#nomad_skip_verify: False\n\n# Seconds between updates for job \u0026 allocation pages. Disable with -1. Default 2\n#wander_update_seconds: 2\n\n# Columns to display for Jobs view - can reference Meta keys. Default \"Job,Type,Namespace,Status,Count,Submitted,Since Submit\"\n#wander_job_columns: \"Job,Type,Namespace,Status,Count,Submitted,Since Submit\"\n\n# Columns to display for Tasks for Job view. Default \"Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime\"\n#wander_tasks_for_job_columns: \"Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime\"\n\n# Columns to display for All Tasks view. Default \"Job,Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime\"\n#wander_all_tasks_columns: \"Job,Node ID,Alloc ID,Task Group,Alloc Name,Task Name,State,Started,Finished,Uptime\"\n\n# If True, start with compact header. Default False\n#wander_compact_header: False\n\n# If True, start in All Tasks view. Default False\n#wander_start_all_tasks: False\n\n# If True, remove unnecessary gaps between table columns when possible. Default True\n# If you want column positions to remain static as you scroll and filter, set this to False\n#wander_compact_tables: True\n\n# Log byte offset from which logs start. Default 1000000\n#wander_log_offset: 1000000\n\n# If True, start with filtering active on first view. Default False\n#wander_start_filtering: False\n\n# If True, filtering highlights and allows cycling through matches, but does not remove surrounding context. Default True\n#wander_filter_with_context: True\n\n# If True, follow new logs as they come in rather than having to reload. Default True\n#wander_log_tail: True\n\n# If True, copy the full path to file after save. Default False\n#wander_copy_save_path: False\n\n# Topics to follow in event streams, comma-separated. Default \"Job,Allocation,Deployment,Evaluation\"\n# see https://www.nomadproject.io/api-docs/events#event-stream\n#wander_event_topics: \"Job,Allocation,Deployment,Evaluation\"\n\n# Namespace used in stream for all events. \"*\" for all namespaces. Default \"default\"\n#wander_event_namespace: \"default\"\n\n# The jq (https://stedolan.github.io/jq/) query used for parsing general events. \".\" to show entire event JSON. Default is:\n#  .Events[] | {\n#    \"1:Index\": .Index,\n#    \"2:Topic\": .Topic,\n#    \"3:Type\": .Type,\n#    \"4:Name\": .Payload | (.Job // .Allocation // .Deployment // .Evaluation) | (.JobID // .ID),\n#    \"5:ID\": .Payload | (.Job.ID // (.Allocation // .Deployment // .Evaluation).ID[:8])\n#  }\n# The numbering exists to preserve ordering, as https://github.com/itchyny/gojq does not keep the order of object keys\n#wander_event_jq_query: \u003e\n#  .Events[] | {\n#    \"1:Index\": .Index,\n#    \"2:Topic\": .Topic,\n#    \"3:Type\": .Type,\n#    \"4:Name\": .Payload | (.Job // .Allocation // .Deployment // .Evaluation) | (.JobID // .ID),\n#    \"5:ID\": .Payload | (.Job.ID // (.Allocation // .Deployment // .Evaluation).ID[:8])\n#  }\n\n# The jq (https://stedolan.github.io/jq/) query used for parsing allocation-specific events. \".\" to show entire event JSON. Default is:\n#  .Index as $index | .Events[] | .Type as $type | .Payload.Allocation |\n#  .DeploymentStatus.Healthy as $healthy | .ClientStatus as $clientStatus | .Name as $allocName |\n#  (.TaskStates // {\"\":{\"Events\": [{}]}}) | to_entries[] | .key as $k | .value.Events[] | {\n#    \"0:Index\": $index,\n#    \"1:AllocName\": $allocName,\n#    \"2:TaskName\": $k,\n#    \"3:Type\": $type,\n#    \"4:Time\": ((.Time // 0) / 1000000000 | todate),\n#    \"5:Msg\": .DisplayMessage,\n#    \"6:Healthy\": $healthy,\n#    \"7:ClientStatus\": $clientStatus\n#  }\n# The numbering exists to preserve ordering, as https://github.com/itchyny/gojq does not keep the order of object keys\n#wander_alloc_event_jq_query: \u003e\n#  .Index as $index | .Events[] | .Type as $type | .Payload.Allocation |\n#  .DeploymentStatus.Healthy as $healthy | .ClientStatus as $clientStatus | .Name as $allocName |\n#  (.TaskStates // {\"\":{\"Events\": [{}]}}) | to_entries[] | .key as $k | .value.Events[] | {\n#    \"0:Index\": $index,\n#    \"1:AllocName\": $allocName,\n#    \"2:TaskName\": $k,\n#    \"3:Type\": $type,\n#    \"4:Time\": ((.Time // 0) / 1000000000 | todate),\n#    \"5:Msg\": .DisplayMessage,\n#    \"6:Healthy\": $healthy,\n#    \"7:ClientStatus\": $clientStatus\n#  }\n\n# For `wander serve`. Hostname of the machine hosting the ssh server. Default \"localhost\"\n#wander_host: \"localhost\"\n\n# For `wander serve`. Port for the ssh server. Default 21324\n#wander_port: 21324\n\n# For `wander serve`. Host key path for wander ssh server\n#wander_host_key_path: \"\"\n\n# For `wander serve`. Host key PEM block for wander ssh server\n#wander_host_key_pem: \"\"\n\n# Custom colors\n#wander_logo_color: \"#DBBD70\"\n```\n\n## Exec Command\n\n`wander` ships with an `exec` command similar to the [`nomad alloc exec`](https://developer.hashicorp.com/nomad/docs/commands/alloc/exec)\nutility. Example usage:\n\n```shell\n# specify job and task, assuming single allocation\nwander exec alright_stop --task redis echo \"hi\"\n\n# specify allocation, assuming single task\nwander exec 3dca0982 echo \"hi\"\n\n# use prefixes of jobs or allocation ids\nwander exec al echo \"hi\"  # prefix of job \"alright_stop\"\nwander exec 3d echo \"hi\"  # prefix of alloc ID \"3dca0982\"\n\n# specify flags for the exec command with --\nwander exec alright_stop --task redis -- echo -n \"hi\"\n```\n\n## SSH App\n\n`wander` can be served via ssh application. For example, you could host an internal ssh application for your company\nsuch that anyone on the internal network can `ssh -p \u003cyour-port\u003e \u003cyour-host\u003e` and immediately access `wander` without\ninstalling or configuring anything.\n\nOptionally, users can pass in their own nomad token with `ssh -p \u003cport\u003e \u003chost\u003e -t \u003ctoken\u003e`. The `-t` argument does not\nstand for token - it forces `ssh` to allocate a pty.\n\nServe the ssh app with `wander serve`.\n\n## Trying It Out\n\nYou can try `wander` out by running a local development nomad cluster following [these instructions](https://learn.hashicorp.com/tutorials/nomad/get-started-run?in=nomad/get-started):\n\n```sh\n# in first terminal session, start and leave nomad running in dev mode\nsudo nomad agent -dev -bind 0.0.0.0 -log-level INFO\n\n# in a different terminal session, create example job and run it\nnomad job init\nnomad job run example.nomad\n\n# run wander\nwander\n```\n\n## Manually Specifying the `wander` Version\n\n`wander` uses [carlmjohnson/versioninfo](https://blog.carlmjohnson.net/post/2023/golang-git-hash-how-to/) to expose\nversion/revision info. If the environment in which you're installing wander does not allow for git repos, prebuilt \nbinaries, or `go install`, then you can manually specify the output of `wander --version` at build time as follows:\n\n```sh\ngo build -ldflags \"-X github.com/robinovitch61/wander/cmd.Version=vX.Y.Z\"\n```\n\nIn this case, you're responsible for ensuring the specified version is in sync with what is actually being built.\n\n## Development\n\nTo manually build:\n\n```shell\ngit clone git@github.com:robinovitch61/wander.git\ncd wander\ngo build  # outputs ./wander executable\n```\n\nThe [scripts](/scripts) directory contains various development helper scripts.\n\nIf the `WANDER_DEBUG` environment variable is set to `true`, the `dev.Debug(s string)` function outputs to `WANDER_DEBUG_PATH` (defaults to `wander.log`).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobinovitch61%2Fwander","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frobinovitch61%2Fwander","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frobinovitch61%2Fwander/lists"}