Documentation Index
Fetch the complete documentation index at: https://mintlify.com/dallay/corvus/llms.txt
Use this file to discover all available pages before exploring further.
Shell Tool
The shell tool enables the agent to execute shell commands in the workspace. It’s one of the most powerful tools, protected by multiple security layers.
Usage
The agent can request shell execution via function calling:
{
"name": "shell",
"arguments": {
"command": "git status"
}
}
Parameters
The shell command to execute
Explicit approval flag for medium/high-risk commands in supervised mode
Security Layers
1. Command Allowlist
Only allowed commands can run (config: autonomy.allowed_commands):
[autonomy]
allowed_commands = ["git", "npm", "cargo", "ls", "cat", "grep"]
2. Risk Classification
Commands are classified by risk:
- Low risk: Read-only commands (e.g.,
ls, cat, git status)
- Medium risk: Write operations (e.g.,
touch, mkdir, git commit)
- High risk: Dangerous operations (e.g.,
rm -rf, chmod, sudo)
In supervised mode, medium/high risk commands require explicit approval:
{
"command": "rm old_file.txt",
"approved": true
}
3. Environment Sanitization
The shell environment is cleared and only safe variables are passed:
const SAFE_ENV_VARS: &[&str] = &[
"PATH", "HOME", "TERM", "LANG", "LC_ALL",
"LC_CTYPE", "USER", "SHELL", "TMPDIR",
];
API keys, secrets, and tokens are never leaked to shell commands.
From src/tools/shell.rs:112-118:
cmd.env_clear();
for var in SAFE_ENV_VARS {
if let Ok(val) = std::env::var(var) {
cmd.env(var, val);
}
}
4. Timeout Protection
Commands are killed after 60 seconds:
const SHELL_TIMEOUT_SECS: u64 = 60;
5. Output Limits
Output is truncated at 1MB to prevent OOM:
const MAX_OUTPUT_BYTES: usize = 1_048_576;
Autonomy Levels
| Level | Behavior |
|---|
| ReadOnly | Shell tool is completely disabled |
| Supervised | Allowed commands only; approval required for risky operations |
| Full | Allowed commands execute without approval |
Runtime Adapters
The shell tool respects the configured runtime:
Native Runtime
Commands execute directly on the host:
let mut cmd = tokio::process::Command::new("sh");
cmd.arg("-c").arg(command);
cmd.current_dir(&self.security.workspace_dir);
Docker Runtime
Commands execute in an isolated container:
[runtime.docker]
image = "alpine:3.20"
network = "none"
memory_limit_mb = 512
read_only_rootfs = true
Example Interactions
Successful Execution
// Input
{"command": "git log --oneline -5"}
// Output
{
"success": true,
"output": "abc1234 feat: add new feature\ndef5678 fix: resolve bug\n...",
"error": null
}
Blocked Command
// Input
{"command": "python script.py"}
// Output (if 'python' not in allowlist)
{
"success": false,
"output": "",
"error": "Command 'python' not allowed by security policy"
}
Timeout
// Input
{"command": "sleep 120"}
// Output
{
"success": false,
"output": "",
"error": "Command timed out after 60s and was killed"
}
Implementation Reference
Source: src/tools/shell.rs
pub struct ShellTool {
security: Arc<SecurityPolicy>,
runtime: Arc<dyn RuntimeAdapter>,
}
#[async_trait]
impl Tool for ShellTool {
fn name(&self) -> &str { "shell" }
fn description(&self) -> &str {
"Execute a shell command in the workspace directory"
}
async fn execute(&self, args: serde_json::Value)
-> anyhow::Result<ToolResult>
{
// Security validation
// Rate limit check
// Command execution with timeout
// Output truncation
}
}
Best Practices
Start with a minimal allowed_commands list and add commands as needed. This reduces attack surface.
Never add sudo, su, chmod +x, or rm -rf to allowed commands in production.