Shell Context Injection in Templates¶
Inject live system context into prompt templates by running shell commands at render time. The !cmd`` syntax executes a command and replaces itself with stdout.
from promptise.prompts import TemplateEngine, SubprocessShellExecutor
engine = TemplateEngine(
shell_executor=SubprocessShellExecutor(timeout=2.0),
)
out = engine.render(
"Today is !`date +%Y-%m-%d`. Branch: !`git rev-parse --abbrev-ref HEAD`.",
{},
)
# "Today is 2026-04-11. Branch: main."
Disabled by default¶
Without an explicit shell_executor, the !cmd`` syntax is left as literal text — there is no implicit shell access, ever. This is a deliberate security choice.
# No executor → syntax stays literal
engine = TemplateEngine()
out = engine.render("Today is !`date`", {})
# "Today is !`date`"
SubprocessShellExecutor¶
The built-in executor runs commands via the system shell with a configurable timeout:
from promptise.prompts import SubprocessShellExecutor
executor = SubprocessShellExecutor(
timeout=5.0, # max seconds per command (default 5)
shell=True, # run via /bin/sh -c (default True)
cwd="/path/to/repo", # working directory (default: inherited)
env={"API_KEY": "x"}, # extra env vars (merged with os.environ)
allowlist={"echo", "date", "git"}, # restrict allowed commands
)
Allowlist¶
When allowlist is set, only commands whose first token matches are permitted:
executor = SubprocessShellExecutor(allowlist={"echo", "git"})
# Works
engine = TemplateEngine(shell_executor=executor)
engine.render("!`echo hello`", {})
# Raises ShellExecutionError
engine.render("!`rm -rf /`", {})
Custom executors¶
Any callable (str) -> str works as a shell executor:
# Dry-run executor for testing
engine = TemplateEngine(shell_executor=lambda cmd: f"[would run: {cmd}]")
# Sandbox executor
async def sandboxed(cmd: str) -> str:
return await sandbox.execute(cmd)
Processing order¶
Shell interpolation runs after template includes and before conditionals and variable substitution. This means:
{% include "name" %}— resolved first (included templates can contain!cmd``)!cmd`` — executed, stdout replaces the block{% if %},{% for %}— conditionals and loops{variable}— variable interpolation
Error handling¶
- Non-zero exit code → raises
ShellExecutionError - Timeout → raises
ShellExecutionError - Command not in allowlist → raises
ShellExecutionError
All errors propagate to the caller — there is no silent fallback.
Related¶
- Loader & Templates — the full template engine reference
- Context & Variables — dynamic context injection via providers