Lightweight alternative to Ansible.
  • TypeScript 99.5%
  • Dockerfile 0.3%
  • Shell 0.2%
Find a file
2026-02-28 23:22:37 +01:00
.zed v0.0.1 2026-02-28 01:17:03 +01:00
example v0.0.1 2026-02-28 01:17:03 +01:00
src v0.1.3: mcp server 2026-02-28 17:07:41 +01:00
tests v0.1.3: mcp server 2026-02-28 17:07:41 +01:00
.gitattributes attributes 2026-02-28 04:13:01 +01:00
.gitignore v0.1.1 2026-02-28 03:54:58 +01:00
AGENTS.md v0.1.3: mcp server 2026-02-28 17:07:41 +01:00
deno.json chore: deps 2026-02-28 17:42:41 +01:00
main.js fix: bundle imports 2026-02-28 17:40:26 +01:00
main.ts v0.0.1 2026-02-28 01:17:03 +01:00
README.md update readme 2026-02-28 23:22:37 +01:00
release.ts fix: bundle imports 2026-02-28 17:40:26 +01:00

Vish

A lightweight alternative to Ansible.

Install

deno install -f -A -g https://vski.sh/x/vish/raw/tag/v1/main.js --name=vish

Or build binary:

deno task build  # creates ./vish

Quick Start

# Bootstrap a new project
vish create project my-infra
cd my-infra
vish create playbook deploy
vish create action pull playbooks/deploy

# Run actions
vish prod1 deploy pull            # Run action on server
vish group:production deploy pull # Run on server group
vish prod1 deploy pull --dry-run  # Preview commands
vish prod1 deploy pull --docker   # Test in Docker container
vish test --docker                # Run all tests in Docker

Project Structure

project/
├── .vish.yaml           # project config
├── .env                 # environment variables
├── .vish.secrets.yaml   # encrypted secrets
├── test.Dockerfile      # custom Docker image for testing (optional)
└── playbooks/
    └── deploy/
        ├── .vish.yaml   # playbook config (optional dependencies)
        ├── check.yaml
        ├── pull.yaml
        ├── build.yaml
        ├── restart.yaml
        └── scripts/     # uploaded files (optional)
            └── build.sh

Config

.vish.yaml:

servers:
  # Simple format: user@host[:port]
  prod1: root@192.168.1.10
  prod2: root@192.168.1.11

  # Extended format with explicit SSH options
  staging:
    host: staging.example.com
    user: deploy
    port: 2222
    identity_file: ~/.ssh/id_rsa_staging
  bastion:
    host: bastion.example.com
    user: admin
    ssh_options:
      StrictHostKeyChecking: 'no'
      UserKnownHostsFile: /dev/null

groups:
  production: [prod1, prod2]

playbooks:
  - ./playbooks/deploy
  - git@github.com:org/shared-playbooks.git # remote playbook

# Custom Docker image for testing
docker:
  dockerfile: test.Dockerfile
  context: .

Server options:

Field Description
host Hostname or IP address
user SSH username (default: root)
port SSH port (default: 22)
identity_file Path to SSH private key
ssh_options Additional SSH options (key/value)

Docker options:

Field Description
dockerfile Path to custom Dockerfile
context Build context directory (default: .)

Uses ~/.ssh/config as fallback for settings not specified in .vish.yaml.

Actions

playbooks/deploy/pull.yaml:

name: pull
description: Pull latest code
depends_on:
  - check
env:
  BRANCH: main
  GIT_REPO: /var/www/app
command: |
  cd $GIT_REPO
  git pull origin $BRANCH

Env priority: action < .env < CLI --env < secrets

File Uploads

Upload files/directories before action execution:

name: build
description: Build application
files:
  - scripts/*.sh
  - config/*.json
env:
  APP_DIR: /var/www/app
command: |
  chmod +x $VISH_FILES_DIR/scripts/*.sh
  $VISH_FILES_DIR/scripts/build.sh
  • files: Glob patterns relative to playbook directory
  • Uploaded files are available in $VISH_FILES_DIR on the server
  • Directories are created automatically

Dependencies

Define pre-execution checks with auto-fix capability:

name: check
description: Check dependencies
dependencies:
  - check: git --version
    ensure: apk add --no-cache git
  - check: curl --version
    ensure: apk add --no-cache curl
command: echo "All dependencies satisfied"
  • check: Command that exits 0 if dependency exists
  • ensure: Command to install/fix if check fails

Dependencies are verified before actions execute on each server. If check fails, ensure runs automatically, then re-checks.

Playbook-level dependencies can be defined in playbooks/deploy/.vish.yaml:

type: playbook
name: deploy
dependencies:
  - check: which node
    ensure: apk add --no-cache nodejs
actions:
  - ./check.yaml
  - ./build.yaml

Project and playbook dependencies are merged at runtime.

Secrets

vish secrets encrypt   # encrypt .vish.secrets.yaml
vish secrets decrypt   # print decrypted to stdout

Password via VISH_SECRETS_PASSWORD env var.

Auto-encrypt on commit:

vish hooks install

Commands

Command Description
vish create project [path] Create project (default: ./)
vish create playbook <name> [path] Create playbook
vish create action <name> [path] Create action
vish list servers List servers and groups
vish list playbooks List playbooks
vish list actions deploy List actions in playbook
vish sync Pull remote playbooks from git
vish test --docker Run tests in Docker containers
vish hooks install Install pre-commit hook

Bootstrap

Generate project scaffolding with templates:

# Create new project
vish create project ./my-infra

# Create playbook (from project dir)
vish create playbook deploy

# Create action (from playbook dir or with path)
vish create action restart
vish create action build ./playbooks/deploy

Generated templates include commented examples for servers, groups, dependencies, and commands.

Flags

Flag Description
--dry-run Preview without execution
--docker Run in Docker containers
--env KEY=VAL Set env var (repeatable)
--check Check if secrets need encryption
--non-interactive Use env var for password
--json Output JSON events (for piping)

Output

By default, vish outputs human-readable text with colors and status indicators:

▶ Running "pull" on 2 server(s)
  Servers: prod1, prod2

[prod1] connecting...
  → check
  ✓ git --version
  → pull
    Already up to date.
  ✓ pull
[prod1] done

[prod2] connecting...
  → check
  ✓ git --version
  → pull
    Already up to date.
  ✓ pull
[prod2] done

✓ All servers succeeded
  2 succeeded, 0 failed

For scripting or piping to tools like jq, use --json:

vish prod1 deploy pull --json | jq -c .

JSON output (one event per line):

{"type":"run_start","servers":["prod1"],"playbook":"deploy","action":"pull"}
{"type":"server_start","server":"prod1"}
{"type":"ensure_start","server":"prod1","check":"git --version"}
{"type":"ensure_check_pass","server":"prod1","check":"git --version"}
{"type":"action_start","server":"prod1","action":"pull"}
{"type":"stdout","server":"prod1","data":"Already up to date.\n"}
{"type":"action_end","server":"prod1","action":"pull","exitCode":0}
{"type":"server_end","server":"prod1","success":true}
{"type":"run_end","results":{"prod1":{"success":true,"exitCode":0}}}

MCP Server

Vish includes an MCP (Model Context Protocol) server for AI agent integration. This allows AI assistants to execute vish commands and track their status asynchronously.

Starting the Server

vish server --project /path/to/project

The server uses stdio transport, making it compatible with MCP clients like Claude Desktop.

Available Tools

Tool Description
list_servers List all servers and groups in the project
list_playbooks List all available playbooks
list_actions List actions in a specific playbook
execute Execute an action on servers (async)
get_status Get execution status and results
get_logs Get execution logs with pagination
cancel Cancel a running execution

Execution Model

The execute tool returns immediately with an execution_id. Use get_status to poll for completion and get_logs to retrieve output:

// Execute action
{"execution_id": "abc123", "status": "running"}

// Check status
{"execution_id": "abc123", "status": "completed", "success": true}

// Get logs
{"logs": [...], "cursor": "token", "has_more": false}

Claude Desktop Configuration

Add to your Claude Desktop config:

{
  "mcpServers": {
    "vish": {
      "command": "vish",
      "args": ["server", "--project", "/path/to/your/project"]
    }
  }
}