CLI Plugin

Execute shell commands on the local machine with output capture, auto-backgrounding for long-running commands, and intelligent shell detection.

Name cli
Type Tool Plugin (Registry-managed)
Tools Provided cli_based_tool
User Commands None
Auto-approved None (requires permission)

Features

  • Shell Detection: Automatically detects pipes, redirections, and chaining
  • Auto-Backgrounding: Long-running commands (>10s) become background tasks
  • Output Truncation: Prevents context overflow from large outputs
  • Smart Duration Estimation: Recognizes slow commands (npm, cargo, etc.)
  • PATH Extension: Add custom directories to command search path
Basic usage
from jaato import PluginRegistry

registry = PluginRegistry()
registry.discover()

# Expose CLI plugin with defaults
registry.expose_tool('cli')

# Or with custom configuration
registry.expose_tool('cli', config={
    'extra_paths': ['/usr/local/bin', '/opt/bin'],
    'max_output_chars': 100000,
    'auto_background_threshold': 30.0,
    'background_max_workers': 8,
})
Model invocation
# The model calls the tool like this:
# cli_based_tool(command="ls -la /home/user")

# Shell features are supported:
# cli_based_tool(command="find . -name '*.py' | head -20")
# cli_based_tool(command="npm install && npm test")

Configuration Parameters

extra_paths

Additional directories to add to PATH when executing commands. Useful when tools are installed in non-standard locations.

TypeList[str]
Default[]

max_output_chars

Maximum characters to return from stdout/stderr combined. Prevents context window overflow from verbose commands.

Typeint
Default50000 (~12k tokens)

auto_background_threshold

Seconds before a command is automatically backgrounded. Commands exceeding this duration return a task handle instead of blocking.

Typefloat
Default10.0

background_max_workers

Maximum concurrent background tasks. Additional tasks queue until a slot opens.

Typeint
Default4
Configuration examples
# Development setup - more output, longer threshold
registry.expose_tool('cli', config={
    'max_output_chars': 100000,
    'auto_background_threshold': 60.0,
})

# CI/CD setup - additional tool paths
registry.expose_tool('cli', config={
    'extra_paths': [
        '/opt/node/bin',
        '/usr/local/go/bin',
        '~/.cargo/bin',
    ],
})

# Resource-constrained - limit background workers
registry.expose_tool('cli', config={
    'background_max_workers': 2,
    'max_output_chars': 20000,
})

Tool Reference

cli_based_tool

Execute any shell command on the local machine.

Parameters

Name Type Required Description
command string Yes Shell command to execute
args string[] No Arguments if passing executable separately

Return Value

Field Type Description
stdout string Command's standard output
stderr string Command's standard error
returncode int Exit code (0 = success)
truncated bool True if output was truncated
error string Error message if execution failed
Tool schema
{
  "name": "cli_based_tool",
  "description": "Execute any shell command...",
  "parameters": {
    "type": "object",
    "properties": {
      "command": {
        "type": "string",
        "description": "The shell command to execute"
      },
      "args": {
        "type": "array",
        "items": {"type": "string"},
        "description": "Optional argument list"
      }
    },
    "required": ["command"]
  }
}
Example responses
// Successful command
{
  "stdout": "total 24\ndrwxr-xr-x  3 user...",
  "stderr": "",
  "returncode": 0
}

// Failed command
{
  "stdout": "",
  "stderr": "ls: /nonexistent: No such file...",
  "returncode": 2
}

// Truncated output
{
  "stdout": "... (truncated)",
  "stderr": "",
  "returncode": 0,
  "truncated": true,
  "truncation_message": "Output truncated..."
}

Auto-Backgrounding

Commands that exceed the auto_background_threshold are automatically converted to background tasks. This prevents the model from blocking on long operations like builds and tests.

Known Slow Commands

The CLI plugin recognizes these patterns as slow operations and estimates their duration for auto-backgrounding decisions:

Pattern Estimated Duration
npm install, yarn install30s
cargo build60s
mvn install60s
docker build60s
pytest, npm test30s
pip install20s
git clone20s
Background Task Integration
When a command is backgrounded, it integrates with the background plugin for task management. The model receives a task handle and can check status or retrieve output later.
Auto-background flow
# Model invokes a slow command:
# cli_based_tool(command="npm install")

# Plugin estimates duration (~30s) > threshold (10s)
# Command runs in background, returns immediately:
{
  "background_task_id": "cli_abc123",
  "status": "running",
  "message": "Command backgrounded due to estimated duration"
}

# Model can check status via background plugin:
# check_background_task(task_id="cli_abc123")

{
  "status": "completed",
  "result": {
    "stdout": "added 1423 packages...",
    "stderr": "",
    "returncode": 0
  }
}

Shell Detection

The CLI plugin automatically detects when a command requires shell interpretation and switches execution modes accordingly.

Shell Mode (shell=True)

Activated when the command contains:

  • Pipes: |
  • Redirections: >, <, >>
  • Command chaining: &&, ||, ;
  • Command substitution: $(), backticks
  • Background execution: & at end

Direct Mode (shell=False)

Used for simple commands without shell metacharacters. Safer and slightly faster, as the command is executed directly without shell parsing.

Shell detection examples
# Direct mode (no shell metacharacters)
cli_based_tool(command="ls -la /home/user")
cli_based_tool(command="git status")
cli_based_tool(command="python script.py --arg value")

# Shell mode (requires shell interpretation)
cli_based_tool(command="find . -name '*.py' | wc -l")
cli_based_tool(command="echo 'hello' > output.txt")
cli_based_tool(command="npm install && npm test")
cli_based_tool(command="cat file.txt || echo 'not found'")
cli_based_tool(command="export FOO=bar; echo $FOO")
Security note
Shell mode passes commands through /bin/sh.
This enables powerful features but also means:

- Shell injection is possible if commands
  contain untrusted input
- The permission plugin should be used to
  review commands before execution
- Consider the security implications of
  allowing shell access in your use case

Error Handling

The plugin's system instructions guide the model on handling common errors:

Error Guidance
Non-zero returncode Check stderr for details
"File exists" Goal already achieved, continue
"Permission denied" Try alternative approach or report blocker
"Command not found" Check if tool installed, try alternative
"No such file" Verify path exists first

Output Truncation

When output exceeds max_output_chars, the response includes a truncated: true flag and guidance message suggesting the model use filters or limits.

Avoiding truncation
# Instead of full output:
find /large/dir -type f

# Use filters to narrow results:
find /large/dir -type f -name "*.py" | head -50

# Limit recursion depth:
find /large/dir -maxdepth 2 -type f

# Use grep to filter:
npm list | grep -E "^[+|`]-- (react|vue)"

# Limit with head/tail:
git log --oneline | head -20