{"id":49772554,"url":"https://github.com/epiral/cli","last_synced_at":"2026-05-11T13:55:31.863Z","repository":{"id":337399293,"uuid":"1151116309","full_name":"epiral/cli","owner":"epiral","description":"Plug any machine into Epiral Agent — shell, files, and browser control in one binary","archived":false,"fork":false,"pushed_at":"2026-02-09T10:04:17.000Z","size":342,"stargazers_count":18,"open_issues_count":2,"forks_count":3,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T13:55:30.719Z","etag":null,"topics":["browser-automation","cli","connectrpc","go","http2","remote-execution"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/epiral.png","metadata":{"files":{"readme":"README.en.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":"2026-02-06T04:23:37.000Z","updated_at":"2026-04-11T16:55:50.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/epiral/cli","commit_stats":null,"previous_names":["epiral/cli"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/epiral/cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epiral%2Fcli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epiral%2Fcli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epiral%2Fcli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epiral%2Fcli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/epiral","download_url":"https://codeload.github.com/epiral/cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/epiral%2Fcli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32897941,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-10T13:40:02.631Z","status":"online","status_checked_at":"2026-05-11T02:00:05.975Z","response_time":120,"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":["browser-automation","cli","connectrpc","go","http2","remote-execution"],"created_at":"2026-05-11T13:55:29.105Z","updated_at":"2026-05-11T13:55:31.856Z","avatar_url":"https://github.com/epiral.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# Epiral CLI\n\n**One binary. Any machine becomes your Agent's extension.**\n\n[![Go](https://img.shields.io/badge/Go-1.25+-00ADD8?logo=go\u0026logoColor=white)](https://go.dev)\n[![License](https://img.shields.io/badge/License-BSL%201.1-orange.svg)](LICENSE)\n\n[中文](README.md) | English\n\n\u003c/div\u003e\n\n---\n\nOne binary, and your machine becomes an extension of [Epiral Agent](https://github.com/epiral/agent). Workstation, VPS, Docker sandbox — the Agent doesn't care what it is, just that it's available.\n\nRegisters as a **Computer** resource (shell + file operations). Built-in web management panel for configuration, logs, and status at a glance.\n\n```\n                      Epiral Agent\n                 ┌──────────────────────┐\n                 │     ComputerHub      │\n                 │  ┌────────────────┐  │\n                 │  │  computers [ ] │  │\n                 │  └────────────────┘  │\n                 └──┬─────────────┬─────┘\n                    │             │\n          ┌─────────┘             └─────────┐\n          │                                 │\n   ┌──────┴──────────┐           ┌──────────┴──────┐\n   │  Epiral CLI      │           │  Epiral CLI      │\n   │  my-pc           │           │  homelab         │\n   │                  │           │                  │\n   │  Computer ✓      │           │  Computer ✓      │\n   │  Web UI :19800   │           │  Web UI :19800   │\n   └─────────────────┘           └─────────────────┘\n```\n\n## Why\n\nAgents need real machines. But machines are behind NATs, on different networks, in different places.\n\n**Reverse connection**: the CLI connects outward to the Agent. No port forwarding. No SSH. The Agent sees all registered machines and dispatches to any of them.\n\nMultiple machines at once, each for a different purpose:\n\n| Scenario | Machine | Why |\n|----------|---------|-----|\n| Daily dev | Workstation | Full dev environment, IDE configs |\n| Untrusted scripts | Docker sandbox | Run and throw away |\n| GPU training | Cloud server | Rent on demand, disconnect when done |\n| Deploy testing | VPS | Simulates production |\n\nThe Agent routes tasks to the right machine. Dangerous ops go to a sandbox. The Agent is always safe.\n\n## Quick Start\n\n### Install\n\n```bash\ngit clone https://github.com/epiral/cli.git\ncd cli \u0026\u0026 make build\n# Binary at ./bin/epiral\n```\n\n### Run (Recommended: Web Panel)\n\n```bash\n# Start with the web management panel\n./bin/epiral start\n\n# With custom config and port (multi-instance)\n./bin/epiral start --config ~/.epiral/dev.yaml --port 19802\n```\n\nOpen `http://localhost:19800`, fill in Agent address and Computer ID on the Config page, click Save \u0026 Restart.\n\n### Run (Direct Mode)\n\n```bash\n./bin/epiral \\\n  --agent http://your-agent:8002 \\\n  --computer-id my-machine \\\n  --paths /home/me/projects\n```\n\n## Web Management Panel\n\n`epiral start` launches an embedded web panel (default port 19800):\n\n| Page | Features |\n|------|----------|\n| **Dashboard** | Connection status, Computer info, uptime, reconnect count |\n| **Config** | Visual configuration for Agent/Computer, Save \u0026 Restart |\n| **Logs** | Real-time log stream (SSE), level filtering, scroll and pause |\n\nConfiguration is persisted to `~/.epiral/config.yaml`. Changes automatically restart the daemon — no manual intervention needed.\n\n### Multi-Instance\n\nRun multiple CLI instances on the same machine (e.g., connecting to both dev and prod Agents):\n\n```bash\n# Dev instance\n./bin/epiral start --config ~/.epiral/dev.yaml --port 19800\n\n# Prod instance\n./bin/epiral start --config ~/.epiral/prod.yaml --port 19801\n```\n\nEach instance has its own config file and web port.\n\n## Usage\n\n### `epiral start` (Recommended)\n\n```\nepiral start [flags]\n```\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `--config` | `~/.epiral/config.yaml` | Config file path |\n| `--port` | 19800 | Web panel port |\n\n### `epiral` (Direct Mode)\n\n```\nepiral [flags]\n```\n\n| Flag | Required | Default | Description |\n|------|----------|---------|-------------|\n| `--agent` | **yes** | — | Agent server URL |\n| `--computer-id` | **yes** | — | Machine identifier |\n| `--computer-desc` | no | same as id | Display name |\n| `--paths` | no | unrestricted | Comma-separated allowed paths |\n| `--token` | no | — | Authentication token |\n\n### What gets reported on registration\n\n| Field | Example |\n|-------|---------|\n| OS / Arch | `darwin/arm64` |\n| Shell | `/bin/zsh` |\n| Home | `/Users/kl` |\n| Installed tools | `go 1.25`, `node v22.13.0`, `git 2.47.1` |\n| Allowed paths | `/Users/kl/workspace` |\n\n## Computer Resource\n\n| Operation | Description |\n|-----------|-------------|\n| Shell execution | Streaming stdout/stderr in real-time |\n| File read | With line offset and limit |\n| File write | Auto-creates parent directories |\n| File edit | Find-and-replace, supports replace_all |\n\nAll file operations are restricted to the path allowlist (`--paths`).\n\n## Connection Resilience\n\nTested and tuned on unreliable networks (ZeroTier with ~10% packet loss):\n\n```\nHeartbeat:    ──ping──ping──ping──ping──\n                3s    3s    3s    3s\n\nPong timeout: 10s without pong → disconnect → reconnect\n\nReconnect:    1s → 2s → 4s → 8s → 16s → 30s (cap)\n              └── resets to 1s after 60s stable\n```\n\n| Layer | Mechanism | Timeout |\n|-------|-----------|---------|\n| Application | Ping/Pong heartbeat | 3s interval, 10s deadline |\n| HTTP/2 | ReadIdleTimeout | 30s |\n| HTTP/2 | PingTimeout | 10s |\n| TCP | Dial timeout | 10s |\n\nEach reconnect creates a fresh HTTP/2 transport to avoid reusing broken connections.\n\n## Internals\n\n```\nepiral-cli/\n├── cmd/epiral/\n│   └── main.go              # Entry: subcommand dispatch, signals\n├── internal/\n│   ├── config/\n│   │   └── config.go         # YAML config load/save/Store\n│   ├── daemon/\n│   │   ├── daemon.go          # Connect, register, heartbeat, dispatch\n│   │   ├── manager.go         # Daemon lifecycle (start/stop/restart)\n│   │   ├── exec.go            # Streaming shell execution\n│   │   └── fileops.go         # Read / write / edit files\n│   ├── logger/\n│   │   └── logger.go          # Ring buffer logging + SSE subscriptions\n│   └── webserver/\n│       └── server.go          # Web panel (REST API + embedded SPA)\n├── web/                       # React + Vite + Tailwind frontend source\n├── proto/epiral/v1/\n│   └── epiral.proto           # Protocol definition\n├── gen/                       # Generated protobuf + Connect RPC code\n├── Makefile                   # build · web · generate · lint · check\n└── .golangci.yml              # 14 linters configured\n```\n\n~1500 lines of hand-written Go. The rest is generated.\n\n## Development\n\n```bash\nmake build      # Full build (frontend + Go)\nmake build-go   # Go only (uses existing dist)\nmake web        # Frontend only\nmake dev        # Frontend dev mode (vite dev server)\nmake check      # Format + lint + build (pre-commit)\nmake generate   # Regenerate protobuf code (requires buf)\nmake clean      # Remove build artifacts\n```\n\n### Requirements\n\n- Go 1.25+\n- Node.js 22+ / pnpm — frontend build\n- [buf](https://buf.build/) for protobuf code generation\n- [golangci-lint](https://golangci-lint.run/) for linting\n\n## Roadmap\n\n- [x] Computer: shell execution + file operations\n- [x] Web management panel (Dashboard / Config / Logs)\n- [x] YAML config persistence\n- [x] Multi-instance support (`--config` + `--port`)\n- [ ] Persistent shell sessions (shell pool)\n- [ ] mTLS / token authentication\n- [ ] systemd / launchd service files\n- [ ] Cross-compilation + GitHub Releases\n- [ ] Large file upload/download\n\n## Related\n\n- [Epiral Agent](https://github.com/epiral/agent) — the brain (Node.js)\n\n## License\n\n[BSL 1.1](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepiral%2Fcli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fepiral%2Fcli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fepiral%2Fcli/lists"}