Example: python -m http.server
First, a trivial example. Outer Shell only needs to know:
- which systemd unit or launchd plist starts/stops the backend
- which localhost port the app uses
This example serves files from your home directory on localhost:8000.
Linux
Create ~/.config/systemd/user/com.example.HttpServer.service:
[Unit]
Description=Example Python HTTP server
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 -m http.server 8000 --directory %h
Restart=on-failure
[Install]
WantedBy=default.target
Enable the unit:
systemctl --user daemon-reload
systemctl --user enable com.example.HttpServer.service
Register it with Outer Shell:
outerctl backend upsert \
--backend com.example.HttpServer \
--name "HTTP Server" \
--systemd-unit com.example.HttpServer.service
outerctl app upsert \
--backend com.example.HttpServer \
--name "HTTP Server" \
--scheme http \
--host 127.0.0.1 \
--port 8000 \
--path /
When the user opens the app, Outer Shell can start
com.example.HttpServer.service, then connect to 127.0.0.1:8000.
Because these examples omit --frontend-id, outershelld derives the app’s
frontend id as <backend>:main.
macOS
Create ~/Library/LaunchAgents/com.example.HttpServer.plist.
Replace /Users/example with your home directory:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.example.HttpServer</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/env</string>
<string>python3</string>
<string>-m</string>
<string>http.server</string>
<string>8000</string>
<string>--directory</string>
<string>/Users/example</string>
</array>
<key>WorkingDirectory</key>
<string>/Users/example</string>
<key>StandardOutPath</key>
<string>/tmp/com.example.HttpServer.log</string>
<key>StandardErrorPath</key>
<string>/tmp/com.example.HttpServer.log</string>
</dict>
</plist>
Bootstrap it:
launchctl bootstrap "gui/$(id -u)" "$HOME/Library/LaunchAgents/com.example.HttpServer.plist"
Register it with Outer Shell:
outerctl backend upsert \
--backend com.example.HttpServer \
--name "HTTP Server" \
--launchd-plist "$HOME/Library/LaunchAgents/com.example.HttpServer.plist"
outerctl app upsert \
--backend com.example.HttpServer \
--name "HTTP Server" \
--scheme http \
--host 127.0.0.1 \
--port 8000 \
--path /
This is intentionally boring. The app process owns the TCP listener, and Outer Shell just starts the service and opens the registered endpoint.