Skip to main content

A lightweight agent runtime that turns any machine into an AI-agent-ready compute target

Project description

agent-runtime

A lightweight agent runtime that turns any machine into an AI-agent-ready compute target. Zero dependencies. Self-updating. Works with any ACP-compatible coding agent.

What is this?

agent-runtime is a sidecar you install on any machine (Dev Box, VM, cloud instance) to make it remotely controllable by AI coding agents. It provides:

  • Async command serverPOST /exec → job ID, GET /jobs/{id} → poll for results
  • WebSocket terminal — interactive ConPTY sessions over WebSocket (xterm.js compatible)
  • ACP client — structured Agent Client Protocol communication with any ACP agent
  • Self-updatingPOST /update triggers graceful upgrade via pip
  • Devtunnel integration — persistent tunnels, token rotation, challenge-code registration
  • API key auth — auto-generated keys, persisted across restarts

Install

# Core (zero dependencies)
pip install devpilot-agent

# With interactive terminal support (Windows)
pip install devpilot-agent[terminal]

Quick Start

# Start the server
agent-server

# Start on a custom port
agent-server --port 9090

# Start with devtunnel + auto-registration
agent-server --wrapper --tunnel --register https://your-dashboard.example.com

# Start with self-update wrapper
agent-server --wrapper

API reference

Authentication

  • GET /health works without an API key, but unauthenticated callers only get a minimal response: {"status":"ok","authenticated":false}
  • All other endpoints require X-API-Key.
  • With a valid API key, GET /health returns the full server capabilities payload.

POST /exec

Submit a shell or ACP job. Successful requests return 202 Accepted with:

{"jobId":"abc123","status":"pending"}

Common request fields:

Field Type Required Notes
mode string no "shell" by default; set to "acp" for ACP mode
workdir string no Working directory for the child process
timeout integer no Timeout in seconds; defaults to 300
env object no Optional environment overlay. Keys and values must both be strings or the request fails with 400.

Shell mode

Shell mode runs the command in a background subprocess.

Field Type Required Notes
command string yes Shell command to execute

Example:

curl -X POST http://localhost:8585/exec \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "python -c \"import os; print(os.environ.get(\\\"DEVPILOT_TEST_ENV\\\", \\\"\\\"))\"",
    "workdir": "C:/src/repo",
    "timeout": 300,
    "env": {
      "DEVPILOT_TEST_ENV": "hello-from-env"
    }
  }'

The env overlay is merged onto the runtime process environment before the shell subprocess starts.

ACP mode

ACP mode launches an ACP-compatible agent and returns structured execution results.

Field Type Required Notes
agent string no ACP launcher command; defaults to copilot --acp --stdio
prompt string no Prompt text to send after session creation/load
acp_session_id string no Resume an existing ACP session
model string no ACP config option
effort string no ACP reasoning effort

Example:

curl -X POST http://localhost:8585/exec \
  -H "X-API-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "acp",
    "agent": "copilot --acp --stdio",
    "prompt": "Implement the login feature",
    "workdir": "C:/src/repo",
    "env": {
      "DOTNET_ROOT": "C:/Users/alice/AppData/Local/Microsoft/dotnet"
    }
  }'

In ACP mode, the env overlay is applied to:

  • the ACP agent subprocess itself
  • any terminal subprocesses created through ACP terminal/create

GET /jobs/{id}

Poll a single job by ID.

Common response fields:

Field Type Notes
jobId string Job identifier
status string pending, running, completed, failed, or timeout
command string Original shell command or [acp] ... launcher
submittedAt number Unix timestamp
lastOutputAt number Updated when output arrives
processAlive boolean Whether the tracked subprocess is still running

Shell jobs add fields such as stdout, stderr, exitCode, durationMs, and timedOut.

ACP jobs add fields such as:

  • acpSessionId
  • stopReason
  • events
  • acpError (when ACP execution fails)

Example:

curl http://localhost:8585/jobs/abc123 -H "X-API-Key: $KEY"

GET /jobs

Returns the most recent jobs (up to 20), newest first. Each item is the same sanitized shape returned by GET /jobs/{id}.

POST /jobs/{id}/nudge

Writes a newline to the running job's stdin. This is mainly useful for shell commands that are waiting for input or need output to flush.

Example:

curl -X POST http://localhost:8585/jobs/abc123/nudge -H "X-API-Key: $KEY"

Response shape:

{"nudged":true,"processAlive":true}

If the process is already finished or no stdin is available, the endpoint returns nudged: false with a reason.

GET /health

Unauthenticated example:

curl http://localhost:8585/health
{"status":"ok","authenticated":false}

Authenticated example:

curl http://localhost:8585/health -H "X-API-Key: $KEY"
{
  "status": "ok",
  "version": "0.2.2",
  "hostname": "devbox-01",
  "jobs": 0,
  "cwd": "C:\\\\src\\\\agent-runtime",
  "authenticated": true,
  "terminal_supported": true,
  "terminal_sessions": 0,
  "acp_supported": true,
  "execution_modes": ["shell", "acp"]
}

POST /update

Triggers a graceful restart for self-update. The server returns 409 instead when jobs are still running or terminal sessions are active.

curl -X POST http://localhost:8585/update -H "X-API-Key: $KEY"

ACP Client (Standalone)

The headless ACP client can be used independently for driving any ACP agent from Python:

from agent_runtime.acp_client import run_acp_session_sync, HeadlessApprovePolicy

result = run_acp_session_sync(
    agent_cmd=["copilot", "--acp", "--stdio"],
    prompt="Refactor the auth module",
    workdir="/path/to/repo",
    timeout=600,
    env={"DOTNET_ROOT": "/home/alice/.dotnet"},
    permission_policy=HeadlessApprovePolicy("/path/to/repo"),
)

print(result.output_text)       # Agent's response
print(result.session_id)        # For session continuity
print(result.tool_calls)        # Structured tool call data
print(result.stop_reason)       # "end_turn", "timeout", "error"

env is optional and overlays string key/value pairs onto the current process environment for the ACP agent subprocess and ACP-created terminal subprocesses.

Architecture

┌─────────────────────────────────────────────────────┐
│  Your Orchestrator / Dashboard / CI                  │
│  (any HTTP client)                                   │
└────────┬─────────────────────┬──────────────────────┘
         │ HTTP                 │ WebSocket
         ▼                     ▼
┌─────────────────────────────────────────────────────┐
│  agent-runtime (on the target machine)               │
│                                                      │
│  ┌───────────────────┐  ┌─────────────────────────┐ │
│  │ Command Server     │  │ Terminal Server          │ │
│  │ :8585              │  │ :8586 (WebSocket)        │ │
│  │                    │  │                          │ │
│  │ POST /exec         │  │ ConPTY ↔ xterm.js       │ │
│  │ GET /jobs/{id}     │  │ JSON input/raw output    │ │
│  │ POST /nudge        │  │ Resize, idle timeout     │ │
│  │ POST /update       │  │ Max 2 sessions           │ │
│  └───────────────────┘  └─────────────────────────┘ │
│                                                      │
│  ┌─────────────────────────────────────────────────┐ │
│  │ ACP Client (headless)                            │ │
│  │ JSON-RPC over stdio → any ACP agent              │ │
│  │ Permission policies, session continuity          │ │
│  └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘

Key Design Decisions

  • Zero runtime dependencies — stdlib-only Python. Terminal extras are opt-in.
  • Async job pattern — fire-and-forget commands avoid tunnel timeout issues.
  • Self-updating — exit code 42 triggers pip upgrade + restart via the wrapper loop.
  • Security — auto-generated API keys, workdir-scoped permission policies, path traversal protection.

Configuration

Environment Variable Default Description
agent_runtime_API_KEY auto-generated API key for authenticating requests
DEVPILOT_TUNNEL_URL Devtunnel URL (set automatically with --tunnel)
DEVPILOT_TUNNEL_TOKEN Devtunnel access token

License

Apache 2.0 — see LICENSE for details.

Releasing

Releases are automated via GitHub Actions. The checked-in publish workflow runs when a version tag is pushed, and the normal flow is:

  1. Bump agent_runtime/__init__.py
  2. Run tests and build locally
  3. Commit and push main
  4. Fast-forward and push the release branch
  5. Push vX.Y.Z to trigger PyPI publish

Example for 0.2.2:

# 1. Bump version in agent_runtime/__init__.py
#    __version__ = "0.2.2"

# 2. Validate the release locally
python -m pytest tests/ -q
python -m build

# 3. Commit and push main
git checkout main
git add agent_runtime/__init__.py README.md agent_runtime/ tests/
git commit -m "Release 0.2.2"
git push origin main

# 4. Fast-forward the shared release branch
git checkout release
git merge --ff-only main
git push origin release

# 5. Push the version tag — this triggers .github/workflows/publish.yml
git checkout main
git tag v0.2.2
git push origin refs/tags/v0.2.2

The publish workflow runs:

  1. Windows tests
  2. Source distribution + wheel build
  3. PyPI publish via Trusted Publisher

If Trusted Publisher is unavailable, the fallback is:

python -m build
python -m twine upload dist/devpilot_agent-0.2.2*

Use a PyPI API token for twine upload. The preferred path is still the tag-triggered GitHub Actions publish.

First-time setup (one-time on pypi.org):

  1. Go to pypi.org/manage/project/devpilot-agent/settings/publishing/
  2. Add trusted publisher: owner=joerob-msft, repo=agent-runtime, workflow=publish.yml, environment=pypi
  3. Create a pypi environment in GitHub repo settings (Settings → Environments → New)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

devpilot_agent-0.2.2.tar.gz (38.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

devpilot_agent-0.2.2-py3-none-any.whl (32.5 kB view details)

Uploaded Python 3

File details

Details for the file devpilot_agent-0.2.2.tar.gz.

File metadata

  • Download URL: devpilot_agent-0.2.2.tar.gz
  • Upload date:
  • Size: 38.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for devpilot_agent-0.2.2.tar.gz
Algorithm Hash digest
SHA256 0c83c5764671809c244ff88ef5dcffef85a95ebb680e1581c38b3fbb1a41d6d5
MD5 e0809aacefe9290dd8197eb0cf62c36e
BLAKE2b-256 6c6a9131bb82075a5f23c3bd9cb68a6bf658a8b88b0336c0ca1de0d4447a87a7

See more details on using hashes here.

File details

Details for the file devpilot_agent-0.2.2-py3-none-any.whl.

File metadata

  • Download URL: devpilot_agent-0.2.2-py3-none-any.whl
  • Upload date:
  • Size: 32.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.13

File hashes

Hashes for devpilot_agent-0.2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c71d45ad41be2520308851a9d2b262df8e5ab1a5cb24af840ff97465e2610be9
MD5 dea95e288fbcae3cc460584612d361a5
BLAKE2b-256 27634c4fce2c286b4da899661a55ff70dbe8b08374170f5cc2821bae0a11841c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page