Real-world usage examples for Terminal.
Reminder: Terminal is a command filter, not a sandbox. All examples below should be combined with OS-level hardening. See Security for chroot, containers, and unprivileged users.
Filter AI agent commands before execution with a strict safeguard configuration:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['/home/ai-agent/projects'],
commands: {
// Only allow specific safe commands. Never allow interpreter wildcards.
allow: [
'git status',
'git log *',
'git diff *',
'git branch *',
'ls *',
'cat *',
'head *',
'tail *',
'wc *',
'echo *',
'npm run build',
'npm run test',
'npm run lint',
'npm install',
'npm ci'
],
// Explicitly block dangerous commands and all interpreters
deny: [
'rm *',
'sudo *',
'chmod *',
'mv * /',
'cp * /',
'sh *',
'bash *',
'curl *',
'wget *',
'nc *',
'python3 *',
'node *',
'deno *'
],
maxArgs: 10,
strictArgs: true, // Blocks ; | & ` $ ( ) { } [ ] < > and ../
noShell: true // Direct execution only
},
env: {
allow: ['NODE_ENV', 'PATH'],
deny: ['HOME', 'SSH_*', 'AWS_*', 'TOKEN*', 'SECRET*', 'LD_PRELOAD', 'LD_LIBRARY_PATH']
},
timeout: 30000,
uid: 1000, // Drop privileges at spawn time
gid: 1000
})
export async function safeExecute(command: string): Promise<string> {
try {
const result = await Terminal.execute(command, {
cwd: '/home/ai-agent/projects',
timeout: 15000
})
if (result.exitCode !== 0) {
return `Error (exit ${result.exitCode}): ${result.stderr}`
}
return result.stdout
} catch (error) {
return `Blocked: ${(error as Error).message}`
}
}Why this config is safer:
- No interpreter wildcards -
python3 *,node *,deno *are denied. An LLM that can run arbitrary scripts can bypass any command filter. - Specific commands only -
git statusis allowed, butgit *is not. This prevents git aliases or hooks from being abused. - strictArgs + noShell - Blocks shell injection (
echo; rm -rf /), command chaining (&&,||), and path traversal (../). - Privilege dropping -
uid/gidruns the child as an unprivileged user, even if the parent has elevated permissions.
Do NOT allow
node *.jsorpython3 *.pyunless you control every file in the workspace. See Interpreter Usage.
Restrict build scripts:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['/workspace'],
commands: {
allow: ['npm run *', 'npm install', 'npm ci', 'echo *', 'ls *'],
deny: ['npm publish', 'npm unpublish', 'rm *', 'git push *', 'git reset *'],
maxArgs: 10,
strictArgs: true,
noShell: true
},
timeout: 300000
})For safely running read-only commands:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['/readonly-data'],
commands: {
allow: ['echo *', 'cat *', 'ls *', 'wc *', 'head *', 'tail *'],
deny: ['rm *', 'mv *', 'cp *', '>', '>>'],
maxArgs: 5,
strictArgs: true,
noShell: true
},
timeout: 10000
})This is not a sandbox.
cat /etc/passwdis allowed because Terminal only checks the command string. Use filesystem permissions (chmod) to enforce read-only access.
Run commands on file changes:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['/project'],
commands: {
allow: ['npm run build', 'npm run test', 'echo *'],
deny: ['rm *', 'sudo *'],
maxArgs: 5,
strictArgs: true,
noShell: true
}
})
async function onFileChange(filepath: string): Promise<void> {
if (filepath.endsWith('.ts')) {
const result = await Terminal.execute('npm run build', {
cwd: '/project',
timeout: 60000
})
console.log(result.exitCode === 0 ? 'Build successful' : 'Build failed')
}
}Track multiple background tasks:
import Terminal from '@neabyte/terminal'
async function runMonitoredTasks(): Promise<void> {
const tasks = [
{ name: 'Database', cmd: 'docker start postgres' },
{ name: 'Cache', cmd: 'docker start redis' },
{ name: 'Server', cmd: 'node server.js' }
]
for (const task of tasks) {
const { id } = await Terminal.execute(task.cmd, {
cwd: '/project',
background: true
})
console.log(`Started ${task.name}: ${id}`)
}
setInterval(() => {
const processes = Terminal.getList()
console.log('\n--- Active Processes ---')
for (const proc of processes) {
console.log(`${proc.id}: ${proc.command} (${proc.running ? 'running' : 'stopped'})`)
}
}, 5000)
}Run commands as an unprivileged user:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['/workspace'],
commands: {
allow: ['git *', 'npm *', 'echo *'],
deny: ['rm *', 'sudo *'],
maxArgs: 10,
strictArgs: true,
noShell: true,
killSignal: 'SIGTERM'
},
env: {
allow: ['NODE_ENV', 'PATH'],
deny: ['HOME', 'SSH_*', 'AWS_*']
},
timeout: 30000,
uid: 1000,
gid: 1000
})
const result = await Terminal.execute('git status', {
cwd: '/workspace'
})Note:
uid/gidrequire the parent process to have permission to change to the target identity. Combine with OS-level unprivileged users for real isolation.
Prevent console window pop-ups and argument injection on Windows:
import Terminal from '@neabyte/terminal'
Terminal.initialize({
workspaces: ['C:\\workspace'],
commands: {
allow: ['echo *', 'dir *'],
deny: ['del *', 'format *'],
maxArgs: 5,
strictArgs: true,
noShell: true,
windowsHide: true,
windowsVerbatimArguments: true
},
timeout: 10000
})- Security - OS-level hardening guide
- Configuration - Customize for your use case
- Common Errors - Troubleshoot issues