A Node.js wrapper for integrating Kiro CLI with OpenClaw's ACP (Agent Control Protocol) runtime, enabling persistent multi-message coding sessions.
This wrapper acts as a bridge between OpenClaw's acpx runner and kiro-cli acp, solving a critical process lifecycle issue:
Problem: kiro-cli spawns a child process (kiro-cli-chat) that doesn't exit when the parent terminates, causing "Session is active in another process" errors on subsequent messages.
Solution: The wrapper explicitly discovers and kills all descendant processes with proper delays, ensuring clean session handoffs and enabling true session persistence.
- ✅ Persistent Sessions - Maintains conversation context across multiple messages
- ✅ Clean Process Cleanup - Kills entire process tree including
kiro-cli-chat - ✅ Argument Forwarding - Supports
--agent,--model, and--trust-all-toolsflags - ✅ Optional Logging - Debug traffic via
KIRO_ACP_WRAPPER_LOGenvironment variable
Ensure kiro-cli is installed and available in your PATH:
which kiro-cliIf not installed, follow the Kiro CLI installation guide.
Add to your ~/.acpx/config.json:
{
"agents": {
"kiro": {
"command": "/home/node/kiro-acp/kiro-acp-wrapper.js",
"runtime": "acp",
"description": "Kiro CLI development agent"
}
}
}{
"agents": {
"kiro": {
"command": "/home/node/kiro-acp/kiro-acp-wrapper.js",
"runtime": "acp",
"description": "Kiro CLI development agent",
"env": {
"KIRO_ACP_WRAPPER_LOG": "/tmp/kiro-acp.log"
}
}
}
}{
"agents": {
"kiro-custom": {
"command": "/home/node/kiro-acp/kiro-acp-wrapper.js --agent my-agent --model claude-sonnet-4 --trust-all-tools",
"runtime": "acp",
"description": "Kiro with custom configuration"
}
}
}Spawn a persistent kiro session:
sessions_spawn({
agentId: "kiro",
runtime: "acp",
mode: "session",
thread: true,
task: "Help me refactor this code"
})Send follow-up messages:
sessions_send({
sessionKey: "agent:kiro:acp:<session-id>",
message: "Now add error handling"
})# Direct usage (for testing)
acpx --agent kiro- Spawns kiro-cli with
detached: trueto create separate process group - Pipes I/O between acpx and kiro-cli with optional logging
- On cleanup (stdin close or SIGTERM):
- Uses
pgrep -P <pid>to find all descendant processes - Kills descendants first (SIGTERM)
- Waits 1 second for descendants to exit
- Kills main process (SIGTERM)
- Waits 1 second for main process to exit
- Wrapper exits after 1.5 second delay
- Uses
- Total cleanup time: ~3.5 seconds ensures session locks are released
Enable logging to debug issues:
# Set in acpx config or export manually
export KIRO_ACP_WRAPPER_LOG=/tmp/kiro-acp.log
# View logs
tail -f /tmp/kiro-acp.logLog entries show:
[IN]- Messages from acpx to kiro-cli[OUT]- Messages from kiro-cli to acpx[ERR]- Stderr output from kiro-cliSpawned kiro-cli PID: <pid>- Process creationFound descendants: <pids>- Child process discoveryKilled descendant <pid>- Cleanup actionsCHILD EXIT: code=<code> signal=<signal>- Process termination
This means a previous kiro-cli process didn't exit cleanly. Solutions:
-
Kill zombie processes:
pkill -9 kiro-cli pkill -9 kiro-cli-chat
-
Check if cleanup delays are sufficient:
- Enable logging and check if descendants are being killed
- Look for "Killed descendant" messages in logs
-
Verify pgrep is available:
which pgrep
This is expected behavior when kiro-cli encounters errors. Check:
- kiro-cli is properly installed:
kiro-cli --version - You're authenticated:
kiro-cli login - The session ID is valid
The KIRO_ACP_WRAPPER_LOG environment variable must be set in the acpx config, not in your shell. Verify:
# Check acpx config
cat ~/.acpx/config.json | grep -A 5 kiro- Node.js - For running the wrapper script
- kiro-cli - Installed and available in PATH
- OpenClaw - With acpx support
- pgrep - For finding descendant processes (standard on Linux/macOS)
kiro-cli spawns kiro-cli-chat as a detached child process. When kiro-cli exits, kiro-cli-chat continues running and holds the session lock. Standard process group killing doesn't work because kiro-cli-chat is in a different process group.
The wrapper solves this by:
- Using
pgrep -P <pid>to find all children - Explicitly killing each child process
- Waiting for processes to fully exit before the wrapper exits
Processes don't exit instantly when sent SIGTERM. They need time to:
- Flush buffers
- Close file handles
- Release locks
- Clean up resources
The 1-second delays after killing ensure processes have fully exited and released session locks before the next wrapper instance starts.
# Clone/navigate to project
cd ~/kiro-acp
# View git history
git log --oneline
# Test changes
echo "" > /tmp/kiro-acp.log
# ... spawn session and test ...
cat /tmp/kiro-acp.logThis project is licensed under the Public Domain (Unlicense). See LICENSE for details.