Skip to content

Feature Request: Shell command execution on client #8

@kieranklaassen

Description

@kieranklaassen

Summary

I'd love to see support for executing shell commands on the client machine. This would unlock powerful CLI tool workflows that need to interact with the user's local environment.

Related to #5 (File and directory access entitlements) - both features would benefit from the same entitlement/permission system.

Use Cases

1. Running project commands

# Run tests and stream output back to server
def run_tests
  result = client.shell.exec("bundle exec rspec", stream: true)
  say "Tests #{result.success? ? 'passed' : 'failed'}"
end

# Run linter
def lint
  client.shell.exec("rubocop --autocorrect")
end

2. Git operations

# Get current branch (alternative to reading .git/config per #5)
def current_branch
  client.shell.exec("git branch --show-current").stdout.strip
end

# Create and push a branch
def create_feature_branch(name)
  client.shell.exec("git checkout -b feature/#{name}")
  client.shell.exec("git push -u origin feature/#{name}")
end

3. Project scaffolding / code generation

# Generate Rails scaffold based on server-side AI analysis
def generate_model(name, fields)
  client.shell.exec("rails generate model #{name} #{fields.join(' ')}")
end

# Install dependencies
def setup_project
  client.shell.exec("bundle install")
  client.shell.exec("yarn install")
  client.shell.exec("rails db:setup")
end

4. Deployment workflows

# Deploy with server-coordinated steps
def deploy
  say "Running pre-deploy checks..."
  client.shell.exec("bundle exec rspec --fail-fast")
  
  say "Building assets..."
  client.shell.exec("rails assets:precompile")
  
  say "Deploying..."
  client.shell.exec("kamal deploy")
end

5. Editor integration

# Open file in user's preferred editor
def edit_config
  client.shell.exec("$EDITOR config/settings.yml")
end

# Open PR in browser
def open_pr(number)
  client.shell.exec("gh pr view #{number} --web")
end

Security Considerations

Shell execution needs careful security design. Since everything is denied by default, users just need a way to allowlist specific commands or patterns:

Command allowlists

# ~/.terminalwire/policies/myapp.com.yml
shell:
  allow:
    - "git *"
    - "bundle exec *"
    - "rails *"
    - "npm run *"
    - "kamal *"

Interactive prompts (per #5 discussion)

$ myapp deploy
⚠️  Server requests: execute "bundle exec rspec"
   [D]eny  [O]nce  [A]llow "bundle exec *"  [T]rust this server

Proposed API

# Basic execution
result = client.shell.exec("command")
result.stdout     # => "output"
result.stderr     # => "errors"  
result.exitstatus # => 0
result.success?   # => true

# With options
client.shell.exec("long-command", 
  timeout: 300,            # Max seconds
  stream: true,            # Stream output in real-time
  env: { "FOO" => "bar" }, # Additional env vars
  chdir: "subdir"          # Working directory
)

# Check if command is allowed before running
if client.shell.allowed?("git push")
  client.shell.exec("git push")
end

Real-World Inspiration

This is inspired by tools like:

  • GitHub CLI (gh) - runs git commands, opens browser
  • Heroku CLI - runs local commands, syncs with server
  • Kamal - orchestrates local Docker/git with remote deploys
  • Claude Code - AI coding assistant that runs shell commands

The key insight is that many powerful CLI tools need to be a bridge between server-side logic and client-side execution.


Happy to help design or test this feature!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions