- TypeScript 99.9%
| .zed | ||
| docs | ||
| example | ||
| src | ||
| tests | ||
| .gitattributes | ||
| .gitignore | ||
| .npmrc | ||
| AGENTS.md | ||
| deno.json | ||
| docker-compose.worker.yml | ||
| install.ts | ||
| main.ts | ||
| README.md | ||
Vish
A task execution orchestrator and agent.
To achieve goals vish agent writes playbooks and uses them as muscle memory. Instead of reapiting bash commands on every turn it finds appropriate playbooks and actions reusing past experience.
Note
Very soon, the
vishagent will become a plugin for vigent. I am moving from OpenCode to more flexible agent and NeoVim-based interface
The Playbooks
The playbook concept and approach to the orchestrastration is borrowed from Ansible. In essence a playbook is a solution - an execution algorithm like script o set of scripts. The agent creates and maintains playbooks to avoid coding solutions from scratch or repeating the same actions in each agent loop.
Memory Layers
-
Muscle Memory - VISH uses hybrid retrieval. The vector (semantic) search and keyword search in the playbooks and actions index. The retrived results serve as both prompt augmentation and actionable items when applicable.
-
Long Term Memory - the agent records experience, solved challenges, factual inforamtion into the memory index. The memory index is shared among projects and agent sessions.
-
Long Term Memory - the agent records experience, solved challenges, factual inforamtion into the memory index. The memory index is shared among projects.
Retrieval Architecture
Depending on which model used and other factors, the long term memory layer may not be used. The decisidion whether to remebeber or not is delegated to the agent.
┌────────< VISH AGENT <─────────┐
│ │
│ │
│ ┌──── PLAYBOOKS ────┐ │
│ │ (muscle memory) │ │
└>IN >──────────────────────>OUT>─┘
│ (longterm memory) │
└────MEMORY LAYER────┘
Steering Bias
Even with small models like GPT-OSS 20B, the agent behaves well when we mention playbooks directly, or when desired outcome is well defined and matches playbook descriptions.
However, small models have a tendency to start writing code even when there is a solution in context. One of the solutions is to change the embeddings model. A better solution is to provide short, clear instructions instad of abstract goals.
Writing Playbooks
- Use large models to write and debug new playbooks (GLM-5 is recommended)
- If you are able to communicate exact instructions in short but complete sentences then even small local models do well.
- If you have more complex, abstract tasks its better to use large models.
Recommended Models
- Small/Local: GPT-OSS 20b
- Large/External: GLM-5
Install
deno run -A https://vski.sh/x/vish/raw/main/install.ts
Or build from source:
git clone https://vski.sh/x/vish.git
cd vish
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_DIRon 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 existsensure: 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"]
}
}
}