28 KiB
Companion Programs Design Investigation
Workspace reference: GSP-WORKSPACE.md
This is an investigation-only design report for adding first-class companion/sidecar application support to GSP game servers. No implementation is included here.
Repository layout reviewed:
/Agent-Windows/Agent_Linux/Panel/Website
Note: the repository currently uses Agent_Linux on disk, not Agent-Linux.
1. Current Flow Found
Main Agent Files
Relevant files:
Agent_Linux/ogp_agent.plAgent-Windows/ogp_agent.plPanel/includes/lib_remote.phpPanel/modules/gamemanager/mini_start.phpPanel/modules/gamemanager/home_handling_functions.phpPanel/modules/gamemanager/start_server.phpPanel/modules/gamemanager/stop_server.phpPanel/modules/gamemanager/restart_server.phpPanel/modules/config_games/schema_server_config.xmlPanel/modules/config_games/server_config_parser.phpPanel/modules/config_games/config_servers.phpPanel/modules/config_games/cli-params.php
Agent Startup Directory And Autostart
Both agents define an agent run directory and a startup flag directory:
- Linux:
AGENT_RUN_DIR,GAME_STARTUP_DIR,SCREEN_LOGS_DIR,SCREENRC_FILE - Windows/Cygwin: same general constants, with Windows-specific SteamCMD executable paths
Both agents create/read the startups directory on agent startup. If startup files exist and --no-startups is not set, the agent reads each startup file and calls universal_start_without_decrypt(...) with the saved startup arguments.
Startup files are CSV-like records containing:
home_id, home_path, server_exe, run_dir, startup_cmd, server_port, server_ip, cpu, nice, preStart, envVars, game_key, console_log
These files are useful for agent autostart but should not be treated as runtime status truth.
Screen Usage
Both agents use screen as the shared runtime backend.
Linux:
create_screen_id(SCREEN_TYPE_HOME, $home_id)creates names likeOGP_HOME_000000123.create_screen_cmd(...)returns ascreen -d -m -t ... -S ...command.create_screen_cmd_loop(...)creates a generated shell script named likeOGP_HOME_000000123_startup_scr.sh, then runs that script insidescreen.- The generated shell script loops/restarts the server when autorestart is enabled.
- The script checks for
SERVER_STOPPEDbefore respawning.
Windows/Cygwin:
- Uses the same
create_screen_id(...)naming pattern. create_screen_cmd(...)launches a command inscreen.create_screen_cmd_loop(...)writes_serverStart.bat, then runs it throughcmd /Q /Cinsidescreen.- The generated batch file loops/restarts the server when autorestart is enabled.
- The batch file checks
SERVER_STOPPEDbefore respawning.
Start Flow
Panel start path:
Panel/modules/gamemanager/mini_start.phpbuilds$start_cmd.- It collects XML
pre_start,environment_variables,lock_files, executable name, executable location, port, IP, CPU affinity, nice value, game key, and console log. - It calls
$remote->universal_start(...).
Linux agent start:
universal_start_without_decrypt(...)validates the home path and executable.- It may create a per-game Linux user when that preference is enabled.
- It writes/updates the startup flag file in
GAME_STARTUP_DIR. - It converts
pre_startand environment variables between multiline and startup-safe formats. - It builds the command according to executable type:
.exe/.bat: Wine command.jar: startup command- other:
./server_exe startup_cmd
- It creates a generated shell startup script through
create_screen_cmd_loop(...). - It backs up
screenlogs/screenlog.<screen_id>. - It runs pre-start commands through
run_before_start_commands(...). - It launches the generated command through
sudo_exec_without_decrypt($cli_bin, $owner). - It renices server processes after launch.
Windows/Cygwin agent start:
universal_start_without_decrypt(...)validates the home path and executable.- It converts paths with
cygpath -wa. - It converts
pre_startand environment variables. - It builds Windows commands using
cmd /Q /C start ... /WAIT. - With autorestart enabled, it uses
create_screen_cmd_loop(...)and_serverStart.bat. - Without autorestart, it uses
create_screen_cmd(...). - It backs up
screenlogs/screenlog.<screen_id>. - It runs pre-start commands through
run_before_start_commands(...). - It launches the screen command with
system($cli_bin). - It writes a startup file named
_serverStart.batunderGAME_STARTUP_DIR, though the name is generic rather than per IP/port in the current Windows path.
Stop Flow
Panel stop path:
Panel/modules/gamemanager/stop_server.phpcalls$remote->remote_stop_server(...).- Stop parameters include home ID, IP, port, control protocol, control password, control type, and home path.
Linux agent stop:
stop_server_without_decrypt(...)removes the startup flag for$server_ip-$server_port.- If autorestart is enabled, it creates
SERVER_STOPPEDin the game home. - It attempts a graceful stop when configured:
rconrcon2armabeminecraft
- If graceful stop does not complete, it collects PIDs from the screen session using
get_home_pids(...). - It sends
kill 15, thenkill 9if needed. - It runs
screen -wipe.
Windows/Cygwin agent stop:
stop_server_without_decrypt(...)removes the startup flag.- If autorestart is enabled, it creates
SERVER_STOPPEDin the game home. - It finds the screen PID from
screen -list. - It maps that to a Windows PID using
ps -W. - It calls
cmd /C taskkill /f /fi 'PID eq ...' /T. - It runs
screen -wipe.
Restart Flow
Both agents expose restart_server and restart_server_without_decrypt(...).
The current intended restart flow is:
- Stop server.
- Wait 60 seconds.
- Start server.
That flow is now present in the current agent files. Any companion system should hook into this sequence explicitly:
- Stop companions.
- Stop game server.
- Wait 60 seconds.
- Start game server.
- Start companions after their configured delays.
PID Tracking
Current PID tracking exists but is inconsistent:
- The agents write their own
ogp_agent.pid. - FastDownload has
fd.pid. - Scheduler has
scheduler.pid. - Linux game server child PIDs are discovered from the screen PID with
pgrep -P. - Windows/Cygwin maps a screen PID to a Windows PID through
ps -W. - Some game XML uses the
PID_FILECLI param, for example Source-engine servers. - Windows
_alsoRun.batbehavior expects_alsoRun.pidto contain helper PIDs.
There is no general companion PID registry today.
Marker Files
Relevant marker files:
GAME_STARTUP_DIR/<ip>-<port>startup flag on Linux.- Windows writes a startup file under
GAME_STARTUP_DIR, currently_serverStart.bat. SERVER_STOPPEDin the game home when autorestart is enabled._alsoRun.pidfor the current Windows helper behavior.
SERVER_STOPPED is used by generated autorestart scripts to decide whether to respawn. It should not be used as the source of truth for current runtime status.
Logs
Game screen logs are written under:
screenlogs/screenlog.<screen_id>
The agents call backup_home_log(...) before starting a server. If XML defines console_log, Panel/agent log functions may read the game-specific console log instead.
There is no dedicated companion stdout/stderr log path today.
2. Current Helper Script Behavior
_alsoRun.bat
The clearest current companion behavior is Windows-only.
In Agent-Windows/ogp_agent.pl, create_screen_cmd_loop(...) generates _serverStart.bat. That generated batch file contains:
if exist "_alsoRun.bat" call "_alsoRun.bat"
start ... /wait <game command>
for /f %%p in (_alsoRun.pid) do taskkill /PID %%p /F
This means:
_alsoRun.batis executed before the game server process._alsoRun.pidis read after the game server exits.- Each PID listed in
_alsoRun.pidis force-killed. - This only exists in the Windows/Cygwin agent path.
- It only works when the generated
_serverStart.batloop path is used. - It relies on files in or near the game server working directory.
- It depends on the helper script correctly writing
_alsoRun.pid.
Some DayZ/Arma XML files generate _alsoRun.bat in pre_start. Examples found include:
Panel/modules/config_games/server_configs/dayz_arma2co_win32.xmlPanel/modules/config_games/server_configs/dayz_epoch_mod_win32.xml
Those XML files build _alsoRun.bat to start BEC and use WMIC to find/write the BEC PID into _alsoRun.pid.
Problems:
- The helper file lives in a customer-accessible game area.
- The customer may be able to edit/delete
_alsoRun.bator_alsoRun.pid. - It is Windows-specific.
- PID capture depends on executable path matching and WMIC.
- Cleanup happens after the game process exits, not as a first-class stop action.
- It is not centrally visible to the Panel as companion state.
pre_start
The XML schema supports pre_start.
Panel reads pre_start in:
Panel/modules/gamemanager/mini_start.phpPanel/modules/gamemanager/restart_server.phpPanel/modules/gamemanager/home_handling_functions.php
The value is passed to the agent as $preStart.
Linux behavior:
run_before_start_commands(...)writes${home_path}/prestart_ogp.sh.- It writes each XML line into the shell file.
- It runs
bash prestart_ogp.shas the game owner. - The script removes itself at the end.
Windows/Cygwin behavior:
run_before_start_commands(...)writes_prestart.batin the Windows-converted home path.- It writes each XML line into the batch file.
- It runs
cmd /Q /C start /wait "<_prestart.bat>". - It deletes
_prestart.bat.
Concerns:
pre_startis trusted XML/admin-defined script content, but it executes in/against the customer game home.- It is not structured.
- It is not tracked.
- It is only "before start"; it is not a companion lifecycle model.
- It cannot reliably stop helper processes unless custom script authors implement that themselves.
post_start
The schema and config editor order include post_start.
Found references:
Panel/modules/config_games/schema_server_config.xmlPanel/modules/config_games/config_servers.phpPanel/modules/config_games/xml_tag_descriptions.php- One example XML:
Panel/modules/config_games/server_configs/nexuiz_win.xml
I did not find a start path that reads server_xml->post_start or sends it to the agents. As currently written, post_start appears schema-visible but not operational.
post_install
Both agents include workshop/mod post-install script generation logic. This is install/update-related, not game-server runtime lifecycle management.
post_install should not be used for companion processes because it is not tied to server start/stop/restart.
Custom Fields And Custom Scripts
Custom fields are supported in XML and stored per server. They are used by config replacement logic:
Panel/modules/gamemanager/cfg_text_replace.phpPanel/modules/config_games/schema_server_config.xml
Custom fields can influence config file content. They are not currently a safe or structured way to define executable companion commands.
Customers can also use extra startup parameters where permissions allow. That should not become the companion command source because it would permit arbitrary command injection into managed helper launches.
3. Recommended Method 1
First-Class Companion Programs System
The best design is a first-class, structured companion program system.
Game XML should define the allowed companion programs for that game. The Panel should store per-server choices such as enabled/disabled and optional safe settings. The agent should own runtime launch, PID tracking, log paths, stop, and restart cleanup.
Example XML shape:
<companion_programs>
<program key="bec" name="BattlEye Extended Controls" os="windows">
<enabled_default>0</enabled_default>
<delay_seconds_default>30</delay_seconds_default>
<working_dir>{GAME_PATH}\BEC</working_dir>
<command>Bec.exe</command>
<args>-f Config.cfg</args>
<process_name>Bec.exe</process_name>
<stop_on_server_stop>1</stop_on_server_stop>
<restart_on_server_restart>1</restart_on_server_restart>
<stdout_log>companions/bec.out.log</stdout_log>
<stderr_log>companions/bec.err.log</stderr_log>
</program>
</companion_programs>
Recommended XML fields:
key: stable internal ID.name: display name.os:linux,windows, orany.enabled_default: default panel setting.delay_seconds_default: default delay after game start.working_dir: trusted template path.command: trusted executable/script name or path template.args: trusted default arguments.process_name: optional verification aid only, not the kill target by itself.stop_command: optional graceful stop command.stop_timeout_seconds: default graceful wait.kill_after_timeout: boolean.stop_on_server_stop: boolean.restart_on_server_restart: boolean.stdout_log/stderr_log: relative managed log paths.required_files: optional list for Panel validation.requires_game_online: whether to delay until the game port is online.
Where XML Defines Allowed Companion Programs
Add companion_programs to Panel/modules/config_games/schema_server_config.xml as an optional top-level element.
Only admins/editors of game XML should be able to define:
- executable path
- arguments
- working directory
- stop command
- process name
- default delay
- log paths
Customers should not be able to enter arbitrary commands.
Where Panel Stores Per-Server Settings
Panel should store per-home companion settings in the database, not in customer-editable files.
Possible table:
server_companion_settings (
id INT AUTO_INCREMENT PRIMARY KEY,
home_id INT NOT NULL,
companion_key VARCHAR(64) NOT NULL,
enabled TINYINT(1) NOT NULL DEFAULT 0,
delay_seconds INT NULL,
settings_json LONGTEXT NULL,
UNIQUE KEY uniq_home_companion (home_id, companion_key)
)
settings_json should only contain safe, schema-defined options. Do not allow free-form command or shell text. For example:
- config profile selection
- config file name from an allowed list
- delay override within min/max bounds
- environment preset key
How The Agent Receives Settings
Extend the encrypted XML-RPC start/restart call to include a companion payload, or add a dedicated agent RPC after start:
Recommended:
universal_start(..., companion_payload)for direct lifecycle coupling.server_companion_start(home_id, payload)for explicit start action.server_companion_stop(home_id)for explicit stop action.server_companion_status(home_id)for status display.
The payload should be generated by the Panel from trusted XML plus stored per-server enabled settings.
Payload should contain fully resolved, validated data:
{
"home_id": 123,
"server_ip": "1.2.3.4",
"server_port": 2302,
"companions": [
{
"key": "bec",
"enabled": true,
"delay_seconds": 30,
"working_dir": "/home/ogp_agent/OGP_User_Files/123/BEC",
"command": "Bec.exe",
"args": ["-f", "Config.cfg"],
"stdout_log": "bec.out.log",
"stderr_log": "bec.err.log"
}
]
}
For XML-RPC compatibility, this may be passed as JSON text.
How The Agent Starts Companions
The agent should start companions after the game screen/session has launched.
Recommended approach:
- Use separate
screensessions per companion. - Session naming:
- Game:
OGP_HOME_000000123 - Companion:
OGP_COMPANION_000000123_bec
- Game:
- Write companion runtime state under an agent-controlled path outside the game FTP/file-manager root.
- Start delayed companions through a small agent-owned delay wrapper:
- Linux:
screen -d -m -S OGP_COMPANION_... bash -lc 'sleep 30; cd ...; exec ...' - Windows/Cygwin:
screen -d -m -S OGP_COMPANION_... cmd /Q /C "timeout /t 30 ... && cd /d ... && ..."
- Linux:
This avoids blocking game startup. The Panel can show the game as STARTING/ONLINE independently while companion statuses move through PENDING, STARTING, RUNNING, or FAILED.
How The Agent Records PIDs
Create an agent-owned runtime directory, for example:
<AGENT_RUN_DIR>/companions/<home_id>/
Files:
companions/<home_id>/state.json
companions/<home_id>/pids/<companion_key>.pid
companions/<home_id>/logs/<companion_key>.out.log
companions/<home_id>/logs/<companion_key>.err.log
State should include:
- home ID
- companion key
- screen session name
- agent PID/screen PID
- child PID if known
- command hash or executable path
- start time
- last status
- last error
For Linux:
- Prefer launching through
screen. - Use the screen PID plus child process lookup.
- If possible, make the wrapper write
echo $$and the exec child PID to a PID file. - Use process group/session cleanup where possible.
For Windows/Cygwin:
- Keep
screenfor parity. - Prefer a wrapper that starts the companion and writes the Windows PID to a PID file.
- Use Cygwin
ps -Wor PowerShell/WMIC alternatives where available. - Avoid killing by executable name alone.
How The Agent Stops Companions
Stop by the recorded handle, not by executable name.
Recommended stop order:
- Load
companions/<home_id>/state.json. - For each running companion:
- If
stop_commandexists, run it in the configured working directory. - Wait up to
stop_timeout_seconds. - If still alive and
kill_after_timeout=1, kill only recorded PID/process tree/session. - Close the companion screen session.
- Update state.
- If
- Clean stale PID files only after verifying the process is gone.
Avoid:
pkill Bec.exetaskkill /IM Bec.exe- broad executable-name matching
Those can kill unrelated customer processes.
Restart Behavior
Recommended restart sequence:
- Stop companions for the home.
- Stop game server.
- Wait 60 seconds.
- Start game server.
- Start enabled companions according to delay settings.
Do not let companions survive a restart unless explicitly marked as persistent and safe.
Companion Logging
Companion stdout/stderr should be logged separately from game screen logs.
Recommended default:
<AGENT_RUN_DIR>/companions/<home_id>/logs/<key>.out.log
<AGENT_RUN_DIR>/companions/<home_id>/logs/<key>.err.log
Panel can add a companion log viewer later, separate from the game server log viewer.
For customer visibility, expose logs through the agent RPC after permission checks rather than placing them inside the customer FTP root by default.
Security
This method is secure because:
- Commands come from trusted game XML/admin configuration.
- Customer UI stores only enable/disable and bounded safe settings.
- Runtime files live outside the customer file manager/FTP root.
- The agent launches only known companion keys for the current game config.
- Stop/kill uses recorded PIDs/screen sessions, not executable names.
- Logs are controlled by the agent.
Portability
This method is portable because:
- XML can define Linux and Windows variants with the same logical companion key.
- Agent receives normalized companion payload.
- Both agents use screen sessions.
- PID capture is platform-specific behind the same agent RPC model.
4. Recommended Method 2
Agent-Managed Generated Startup/Cleanup Scripts
Alternate design: keep using scripts, but generate and store them in an agent-controlled directory outside customer-editable game files.
Example layout:
<AGENT_RUN_DIR>/companions/<home_id>/
companions.json
start_companions.sh
stop_companions.sh
start_companions.bat
stop_companions.bat
pids/
logs/
The Panel still defines companions from trusted XML and stores per-server enabled settings. The agent generates scripts from those trusted definitions.
Start flow:
- Game server launches.
- Agent starts an agent-owned companion startup script in its own screen session.
- Script handles delays and PID capture.
Stop flow:
- Agent runs an agent-owned cleanup script.
- Script kills only PIDs listed in the agent-owned
pidsdirectory. - Agent verifies cleanup.
Pros
- Closer to the existing
_serverStart.batand generated shell script model. - Easier to debug for admins because generated scripts are readable.
- Can work with the existing screen backend.
- Avoids customer-editable
_alsoRun.bat. - Can be implemented incrementally.
Cons
- Still script-heavy.
- Quoting rules remain difficult across Linux, Cygwin, and Windows.
- Risk of script injection if generation is not strict.
- PID capture still needs platform-specific care.
- State management can drift if scripts are edited manually by admins.
- Less clean than direct agent-managed process APIs.
Comparison To Method 1
Method 1 is better long term because the agent owns lifecycle state directly. Method 2 is a reasonable migration bridge if implementation speed matters, but it should still use trusted XML/admin definitions and agent-owned control paths.
5. Security Considerations
Do Not Trust Customer-Editable Startup Files
Avoid using customer-editable files such as:
_alsoRun.bat_alsoRun.pid- arbitrary
.bator.shhelper files in the game home
Those files can be edited, deleted, replaced, or used to run unintended commands.
Managed Files Should Live Outside The FTP/File Manager Root
Recommended location:
<AGENT_RUN_DIR>/companions/<home_id>/
This directory should be owned by the agent or game server runner user and should not be directly writable by customers.
Commands Must Come From Trusted Configuration
Companion commands should come from:
- shipped game XML
- admin-managed XML
- a future admin-only companion catalog
They should not come from:
- customer text fields
- startup extra parameters
- uploaded files
- customer-editable config files
Validate Commands
Validation should include:
- companion key exists in the current game XML
- OS matches the agent OS
- command path resolves under an allowed directory unless explicitly admin-approved
- working directory resolves under game home or an admin-approved path
- no unexpanded
{...}tokens remain - no shell metacharacters in fields that are supposed to be argv tokens
- delay is numeric and capped
- log paths are relative and cannot escape managed log directories
Avoid Arbitrary Command Execution
Use argv-style execution where possible.
When shell/batch is unavoidable:
- generate commands from trusted fields only
- quote every path/argument consistently
- avoid concatenating customer-provided strings into shell code
- keep generated files outside customer write paths
Avoid Killing Unrelated Processes
Do not kill by executable name alone.
Preferred kill targets:
- recorded companion PID
- recorded process group
- recorded screen session
- recorded Windows process tree for that PID
Process name should be used only as a verification hint, not as the primary kill selector.
6. Cross-platform Considerations
Linux Agent
Linux can use:
screenbash- PID files
/procpgrep -Pkill 15, thenkill 9
Recommended Linux companion launch:
screen -d -m -S OGP_COMPANION_<home_id>_<key> bash -lc '<agent-owned wrapper>'
Use an agent-owned wrapper or direct fork/exec to record PID and redirect logs.
Windows/Cygwin Agent
Windows/Cygwin can use:
screencmd /Q /Cstarttaskkill /PID ... /Tps -W- possibly WMIC or PowerShell depending on environment
Current _alsoRun.bat depends on WMIC in some XML. WMIC is not reliable on all modern Windows installations, so future code should not require it.
Recommended Windows companion launch:
screen -d -m -S OGP_COMPANION_<home_id>_<key> cmd /Q /C "<agent-owned wrapper.bat>"
The wrapper should record the Windows PID or enough process/session information for cleanup.
Batch vs Shell Differences
Risks:
- quoting spaces in paths
- escaping backslashes
- environment variable syntax differences
startwindow title behavior on Windows- delayed expansion in batch files
- Cygwin path vs Windows path conversion
- signal semantics: Linux signals vs Windows taskkill
The Panel should not build platform command strings. It should send trusted structured definitions to the agent and let the agent perform OS-specific quoting/execution.
Screen Behavior
Screen remains the default shared backend for now.
Use separate screen sessions for companions rather than attaching them to the game server screen. This gives:
- independent status
- independent logs
- safer cleanup
- clearer restart behavior
Process Cleanup Risks
Companion processes may:
- fork children
- daemonize
- spawn background processes
- exit while leaving children
- fail before writing PID
- be started manually by the customer/admin
The agent should track process trees where possible and verify stop results.
7. Suggested Implementation Phases
Phase 1: Inventory Current Flow And Add Report Only
This report is Phase 1.
No source code changes should be made for companion behavior in this phase.
Phase 2: XML Schema Design
Add companion_programs to:
Panel/modules/config_games/schema_server_config.xmlPanel/modules/config_games/config_servers.phpPanel/modules/config_games/xml_tag_descriptions.php
Create example XML for BEC, B3, and a generic log watcher.
Phase 3: Panel Storage/UI Design
Add storage for per-server companion settings.
Initial UI:
- show companion list from XML
- enable/disable checkbox
- delay override
- safe predefined options only
Do not expose raw command editing to customers.
Phase 4: Agent Start/Stop Integration
Add encrypted RPCs:
server_companion_startserver_companion_stopserver_companion_status
Extend start/restart flow to call companion start/stop at the right time.
Phase 5: PID Tracking And Cleanup
Implement:
- agent-owned state directory
- PID files
- screen session names
- process tree cleanup
- stale PID detection
- companion status reporting
Phase 6: DayZ/BEC Test
Migrate one DayZ/Arma BEC case away from _alsoRun.bat.
Test:
- start game
- delayed BEC start
- BEC status
- stop game
- BEC cleanup
- restart flow
- crash/recovery behavior
- agent restart behavior
Phase 7: Generalized Docs
Document:
- XML authoring
- admin setup
- supported placeholders
- security rules
- troubleshooting
- log locations
- migration path from
_alsoRun.bat
8. Open Questions
- Should companions be started after the game process exists, after the game port is listening, or after query/RCON succeeds when available?
- Should companions be allowed to keep running if the game server crashes and autorestarts, or should they always restart with each game process cycle?
- Should some companions be marked "persistent" across game restarts?
- Which user should run companions on Linux when
LINUX_USER_PER_GAME_SERVERis enabled? - Should companion logs be visible to customers by default, or admin-only?
- Should companion config files be editable through the existing config file module?
- How should Windows PID capture work on systems without WMIC?
- Is PowerShell guaranteed available in the supported Windows/Cygwin agent environment?
- Should the Panel support companion install/update packages, or only runtime start/stop of already-installed files?
- Should companion definitions live only in game XML, or should there be a reusable global companion catalog?
- How should firewall rules handle companion ports if a companion needs one?
- What should happen if a companion fails but the game server is online?
- Should companion failure affect billing/status/customer-facing uptime?
- How should agent autostart restore companion state after power loss or agent restart?
- Should the agent stop companions before or after graceful game stop for tools that send shutdown messages to the game?
- Should companion environment variables be separate from game environment variables?
- How should command placeholders be standardized across Linux and Windows?
- What is the maximum acceptable startup delay for companion programs?
- Should admins be able to override companion commands per server, or only per game XML?
- How should existing
_alsoRun.batgame configs be migrated without breaking current customers?
Summary Recommendation
Build Method 1: a first-class companion programs system driven by trusted XML/admin configuration, stored per server in the Panel, and executed/owned by the agent.
Do not continue expanding _alsoRun.bat. It is a useful proof of need, but it is Windows-specific, customer-editable, hard to audit, and unreliable for stop/restart cleanup.
Use screen as the shared backend for now, with one screen session per companion and agent-owned PID/log/state files outside the customer file root.