-
-
Notifications
You must be signed in to change notification settings - Fork 5
Processes and PTY
Manage long-running commands, interactive terminals, stdin, and process completion notifications.
Refact's execution runtime can run commands in the foreground, keep long-running processes in the background, manage named services, and attach interactive commands to a pseudo-terminal (PTY).
Use process tools when a command is long-running, interactive, or should be inspected after it starts.
| Mode | Best for | Lifetime |
|---|---|---|
| Foreground shell | Tests, builds, one-shot diagnostics. | Tool call waits until completion or timeout. |
| Background process | Long-running one-off commands. | Continues after the tool returns; read/wait/kill by process ID. |
| Service | Named dev servers or watchers. | One running service per owner/workspace/name. |
The shell tool can also start a background process with run_in_background: true.
Refact injects stable defaults into exec spawns unless a tool call explicitly overrides them:
NO_COLOR=1
TERM=dumb
LANG=C.UTF-8
LC_CTYPE=C.UTF-8
LC_ALL=C.UTF-8
COLORTERM=
PAGER=cat
GIT_PAGER=cat
GH_PAGER=cat
REFACT_EXEC=1
These defaults avoid ANSI noise, locale drift, and commands blocking in pagers.
Both shell and process_start support tty: true.
Use tty: true for:
- REPLs such as Python, Node, Rails console, or shells;
- CLIs that prompt for input;
- programs that buffer differently unless attached to a terminal;
- debugging interactive flows.
Keep tty: false for normal tests, linters, and build commands.
PTY trade-offs:
- stdout and stderr are merged into the
combinedstream; - output may include prompts and terminal control characters;
- some commands behave differently when they detect a terminal;
- on Windows the backend uses the portable PTY/ConPTY path when available.
Runs a command in the current workspace. Use it for one-shot commands, or set run_in_background: true for a background process.
Schema highlights:
{
"type": "object",
"properties": {
"command": { "type": "string" },
"description": { "type": "string" },
"workdir": { "type": "string" },
"timeout": { "type": "integer" },
"tty": { "type": "boolean", "default": false },
"run_in_background": { "type": "boolean", "default": false }
},
"required": ["command", "description"]
}Examples:
{ "command": "cargo test --lib", "description": "Run Rust unit tests" }{
"command": "npm run dev",
"description": "Start frontend dev server",
"run_in_background": true
}Edge cases:
-
descriptionis required and must be concise. - Numeric
timeoutvalues must be positive integers. -
run_in_backgroundreturns immediately with a process ID; do not add&to the command. - Background shell commands emit a completion event when they exit.
Starts a runtime-owned background or service process.
Schema highlights:
{
"type": "object",
"properties": {
"command": { "type": "string" },
"description": { "type": "string" },
"mode": { "type": "string", "enum": ["background", "service"] },
"service_name": { "type": "string" },
"workdir": { "type": "string" },
"startup_wait_ms": { "type": "integer" },
"startup_wait_port": { "type": "integer" },
"startup_wait_keyword": { "type": "string" },
"tty": { "type": "boolean", "default": false }
},
"required": ["command", "description"]
}Examples:
{
"command": "npm run dev",
"description": "Start web dev server",
"mode": "service",
"service_name": "web",
"startup_wait_port": 5173
}{
"command": "python3 -i",
"description": "Open Python REPL",
"tty": true
}Edge cases:
-
servicemode requiresservice_name. - Starting the same service twice in the same owner/workspace is rejected until you kill the old one.
- Workdirs are resolved through workspace and privacy rules.
Lists runtime-owned processes.
Schema:
{
"type": "object",
"properties": {
"status": { "type": "string", "description": "running, completed, or all" },
"scope": { "type": "string", "description": "chat, workspace, or all" }
},
"required": []
}Use it to rediscover process IDs or audit completed jobs.
Reads buffered output from a process.
Schema highlights:
{
"type": "object",
"properties": {
"process_id": { "type": "string" },
"since_seq": { "type": "integer" },
"stream": { "type": "string", "description": "stdout, stderr, combined, or all" },
"output_filter": { "type": "string" },
"output_limit": { "type": "string" }
},
"required": ["process_id"]
}process_read returns cursor fields such as next_seq and latest_seq. Pass next_seq as the next since_seq to poll for only new output.
Waits for a process to exit, then returns output and metadata. Use it when you expect a background command to complete soon but do not want to poll manually.
Kills a runtime-owned process by ID.
Schema:
{
"type": "object",
"properties": {
"process_id": { "type": "string" }
},
"required": ["process_id"]
}process_write_stdin is the stdin contract for PTY processes.
Schema:
{
"type": "object",
"properties": {
"process_id": { "type": "string" },
"chars": { "type": "string", "default": "" },
"yield_time_ms": { "type": "integer", "default": 250, "maximum": 10000 }
},
"required": ["process_id"]
}Behavior:
- Requires the process to have started with
tty: true. - Writes
charsexactly as provided. - Waits up to
yield_time_msfor new output or exit. -
chars: ""is a poll: it writes nothing and only waits for output. - Output metadata should include
bytes_writtenandchunks_returned.
Examples:
{ "process_id": "exec_123", "chars": "print('hi')\n", "yield_time_ms": 500 }{ "process_id": "exec_123", "chars": "", "yield_time_ms": 1000 }Edge cases:
- Non-PTY process IDs are rejected.
- Include newlines when the process expects Enter.
- Control characters are literal; be deliberate.
When a background or service process exits, Refact injects event(process_completed) into the owning chat. The event payload includes:
{
"process_id": "exec_123",
"status": "exited",
"exit_code": 0,
"duration_ms": 1000,
"short_description": "Run backend server"
}The GUI shows this in the Event log and can scroll to matching process cards when available. Foreground shell commands do not generate background completion events.
- Start long-running work with
process_startorshell+run_in_background. - Keep the
process_idfrom the result. - Use
process_readwith cursors to inspect output. - Use
process_write_stdinonly fortty: truesessions. - Use
process_waitif you expect the process to finish soon. - Use
process_killbefore restarting services or cleaning up work.
Refact on GitHub: https://github.com/JegernOUTT/refact
- Agent Modes
- Agent Tools
- Task Planner & Cards
- Worktrees
- Subagents
- Memory & Knowledge
- Hidden Roles & Plans
- Context Compression
- Scheduler & Cron
- Processes & PTY
- Buddy
- MCP
- Skills, Commands & Hooks
- Marketplace
- Chat System
- Providers
- Caps & Models
- Code Completion (FIM)
- AST
- VecDB
- Exec Runtime
- HTTP API
- Checkpoints & Git
- Voice