{"id":51324208,"url":"https://github.com/datamadsen/devspanner","last_synced_at":"2026-07-01T16:32:45.386Z","repository":{"id":367074604,"uuid":"1279055083","full_name":"datamadsen/devspanner","owner":"datamadsen","description":"A small, config-driven terminal UI for the local dev loop","archived":false,"fork":false,"pushed_at":"2026-06-24T11:57:58.000Z","size":42,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-24T13:24:35.352Z","etag":null,"topics":["bubbletea","cli","dev-environment","developer-tools","go","terminal","tui"],"latest_commit_sha":null,"homepage":null,"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/datamadsen.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":"SECURITY.md","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},"funding":{"github":["datamadsen"]}},"created_at":"2026-06-24T10:28:57.000Z","updated_at":"2026-06-24T11:58:02.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/datamadsen/devspanner","commit_stats":null,"previous_names":["datamadsen/devspanner"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/datamadsen/devspanner","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datamadsen%2Fdevspanner","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datamadsen%2Fdevspanner/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datamadsen%2Fdevspanner/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datamadsen%2Fdevspanner/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datamadsen","download_url":"https://codeload.github.com/datamadsen/devspanner/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datamadsen%2Fdevspanner/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35015053,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-01T02:00:05.325Z","response_time":130,"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","cli","dev-environment","developer-tools","go","terminal","tui"],"created_at":"2026-07-01T16:32:45.228Z","updated_at":"2026-07-01T16:32:45.357Z","avatar_url":"https://github.com/datamadsen.png","language":"Go","funding_links":["https://github.com/sponsors/datamadsen"],"categories":[],"sub_categories":[],"readme":"# devspanner\n\n[![ci](https://github.com/datamadsen/devspanner/actions/workflows/ci.yml/badge.svg)](https://github.com/datamadsen/devspanner/actions/workflows/ci.yml)\n[![release](https://img.shields.io/github/v/release/datamadsen/devspanner?sort=semver)](https://github.com/datamadsen/devspanner/releases)\n[![Go Reference](https://pkg.go.dev/badge/github.com/datamadsen/devspanner.svg)](https://pkg.go.dev/github.com/datamadsen/devspanner)\n[![Go Report Card](https://goreportcard.com/badge/github.com/datamadsen/devspanner)](https://goreportcard.com/report/github.com/datamadsen/devspanner)\n[![License: MIT](https://img.shields.io/github/license/datamadsen/devspanner)](LICENSE)\n\nA small, config-driven terminal UI for the local dev loop. One screen to see and\nsteer everything you juggle while developing locally — a docker stack, app\nbackends, frontends — plus a command palette for the one-shot recipes (build,\ndeploy) that would otherwise clutter the view.\n\n```\n my-project · devspanner\n\n shared                             actions\n   ● platform  up                   [a] all start\n                                     [x] stop apps\n api                                [c] commands\n ➤ ● backend   running   :8080      [g] dashboard\n                                     [q] quit\n web\n   ● frontend  running   :5173\n\n ↑/↓ select   [r] (re)start   [s] stop   [l]ogs   [o]pen in browser\n```\n\n## Why\n\n`docker compose` + a couple of `npm run dev`s + a backend + the odd build/deploy\nscript is a lot of terminals and stale-process footguns. devspanner gives you:\n\n- **Live status \u0026 health** for every service (up / starting / running / stale).\n- **Start / stop / restart** that frees a busy port first (no more \"address already\n  in use\") and tails each service's captured log.\n- **Open in browser** — jump to a frontend or an API docs page.\n- **A command palette** (`c`) for one-shot tasks (build, deploy), run in the\n  background with streamed output, so they never crowd the dashboard.\n- **Ownership that survives restarts** — close devspanner, reopen it, and it still\n  knows which processes it started.\n\nIt's a single static binary; everything it manages lives in a YAML file in your repo.\n\n## Install\n\ndevspanner is Linux-first (macOS works with graceful degradation; see\n[Notes](#notes)). Pick whichever fits:\n\n**Go** (any platform with a Go toolchain):\n\n```bash\ngo install github.com/datamadsen/devspanner@latest\n```\n\n**Arch Linux** (AUR — e.g. with `yay`):\n\n```bash\nyay -S devspanner        # builds from source\n# or: yay -S devspanner-bin   # prebuilt binary\n```\n\n**Homebrew** (macOS / Linux):\n\n```bash\nbrew install datamadsen/tap/devspanner\n```\n\n**Prebuilt binaries \u0026 packages**: grab a `.tar.gz`, `.deb`, or `.rpm` from the\n[Releases](https://github.com/datamadsen/devspanner/releases) page.\n\n**From source**:\n\n```bash\ngit clone https://github.com/datamadsen/devspanner\ncd devspanner \u0026\u0026 make build      # or: go build -o devspanner .\n```\n\n## Quick start\n\n1. Drop a config at your repo root — see [`examples/config.yaml`](examples/config.yaml):\n\n   ```bash\n   mkdir -p .devspanner \u0026\u0026 cp examples/config.yaml .devspanner/config.yaml\n   ```\n\n2. Edit it for your project, then run `devspanner` from anywhere in the repo.\n\ndevspanner finds the repo root (via `git`) and reads `.devspanner/config.yaml`. A\nmissing or invalid config prints a specific error and exits before taking over the\nscreen.\n\n## Configuration\n\n```yaml\nname: my-project            # optional; shown in the header\n\ngroups:                     # display groupings (shared infra, then one per app)\n  - name: api\n    services:               # long-running things — shown on the dashboard\n      - name: backend\n        start: npm run dev  # required\n        port: 8080          # process-style: liveness + free-before-restart\n        dir: services/api   # working dir (relative to repo root); optional\n        health: http://localhost:8080/health   # \u003c500 = healthy; optional\n        open: http://localhost:8080/docs        # [o]pen in browser; optional\n        watch: services/api/src                 # flag build \"stale\" when newer; optional\n    tasks:                  # one-shot recipes — behind the `c` palette, not the dashboard\n      - name: deploy\n        run: ./scripts/deploy.sh\n        confirm: true       # ask y/n before running (use for anything outward-facing)\n\nshortcuts:                  # global keys: open a URL or run a command\n  - key: g\n    label: dashboard\n    open: http://localhost:3000\n```\n\n**Service behaviour is derived from the fields, not a `type`:**\n\n- `container:` → **docker-style**. Liveness = that container running; `start`/`stop`\n  are run as commands; logs come from the `logs:` command.\n- `port:` → **process-style**. devspanner owns the child it spawns, captures its\n  output to `.devspanner/logs/\u003cgroup\u003e-\u003cname\u003e.log`, and frees the port before a\n  restart. `logs:` is optional here — the captured file is tailed.\n\nFull per-field notes are in [`examples/config.yaml`](examples/config.yaml).\n\n## Keys\n\n| Key | Action |\n|-----|--------|\n| `↑`/`↓`, `j`/`k` | move selection |\n| `r` | (re)start selected service |\n| `s` | stop selected service |\n| `l` / `enter` | view logs |\n| `o` | open selected service's URL (only shown when it has one) |\n| `a` | start everything |\n| `x` | stop all process-style services (docker/infra stays up) |\n| `c` | command palette (build/deploy tasks) |\n| `q` | quit |\n\nIn the log/output view: `↑`/`↓` scroll, `esc` back, `x` cancels a running task.\nConfigured `shortcuts` add their own global keys (anything not reserved above).\n\n## Notes\n\n- **Linux**: ownership detection and stale-build timing read `/proc` (env marker +\n  process start time), so a service started by a previous devspanner session is still\n  recognised as \"running\" after you reopen. On other platforms these degrade\n  gracefully (a service is \"owned\" only within the current session).\n- Carriage-return progress output (build timers, docker/npm progress bars) is\n  collapsed the way a terminal would render it, so the log view stays clean.\n- devspanner manages the dev loop; it does not replace your build/deploy scripts — it\n  runs them.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatamadsen%2Fdevspanner","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatamadsen%2Fdevspanner","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatamadsen%2Fdevspanner/lists"}