Python SDK for CMDOP agent interaction
Project description
CMDOP
Your OS. Online.
Full access to your machines from anywhere. Not files — the whole system.
Your Code ──── Cloud Relay ──── Agent (on server)
│
Outbound only, works through any NAT/firewall
Why CMDOP?
| Problem | CMDOP Solution |
|---|---|
| VPN requires client install | SDK works without VPN |
| SSH needs port forwarding | Agent uses outbound connection |
| Screen sharing is laggy | gRPC streaming, real-time |
| File sync is just files | Full OS access: terminal + files |
| AI returns text | Structured output with Pydantic |
| No reusable workflows | Skills: predefined AI tasks with tools |
Install
pip install cmdop
Quick Start
from cmdop import AsyncCMDOPClient
async with AsyncCMDOPClient.remote(api_key="cmdop_xxx") as client:
# Terminal
await client.terminal.set_machine("my-server")
output, code = await client.terminal.execute("uname -a")
# Files
content = await client.files.read("/etc/hostname")
await client.files.write("/tmp/config.json", b'{"key": "value"}')
# AI Agent with typed output
from pydantic import BaseModel
class Health(BaseModel):
cpu: float
memory: float
issues: list[str]
await client.agent.set_machine("my-server")
result = await client.agent.run("Check server health", output_model=Health)
health: Health = result.data # Typed!
# Skills — run predefined AI workflows
await client.skills.set_machine("my-server")
skills = await client.skills.list()
result = await client.skills.run("code-review", "Review the auth module")
Connection
from cmdop import CMDOPClient, AsyncCMDOPClient
# Remote (via cloud relay) - works through any NAT
client = CMDOPClient.remote(api_key="cmdop_xxx")
# Local (direct IPC to running agent)
client = CMDOPClient.local()
# Async
async with AsyncCMDOPClient.remote(api_key="cmdop_xxx") as client:
...
Terminal
Execute commands, stream output, SSH into machines.
async with AsyncCMDOPClient.remote(api_key="cmdop_xxx") as client:
# Set target machine once
await client.terminal.set_machine("my-server")
# Execute and get output
output, code = await client.terminal.execute("ls -la")
print(output.decode())
# Interactive operations
await client.terminal.send_input("echo hello\n")
await client.terminal.resize(120, 40)
await client.terminal.send_signal(SignalType.SIGINT)
SSH-like interactive session:
# CLI
cmdop ssh my-server
# Python
from cmdop.services.terminal.tui.ssh import ssh_connect
asyncio.run(ssh_connect('my-server', 'cmd_xxx'))
Real-time streaming:
stream = client.terminal.stream()
stream.on_output(lambda data: print(data.decode(), end=""))
await stream.attach(session.session_id)
await stream.send_input(b"tail -f /var/log/app.log\n")
Session discovery:
# List all machines
response = await client.terminal.list_sessions()
for s in response.sessions:
print(f"{s.machine_hostname}: {s.status}")
# Get specific machine
session = await client.terminal.get_active_session("prod-server")
Files
Read, write, list files on remote machines. No scp/sftp needed.
# Set target machine once
await client.files.set_machine("my-server")
# File operations
files = await client.files.list("/var/log", include_hidden=True)
content = await client.files.read("/etc/nginx/nginx.conf")
await client.files.write("/tmp/config.json", b'{"key": "value"}')
# More operations
await client.files.copy("/src", "/dst")
await client.files.move("/old", "/new")
await client.files.mkdir("/new/dir")
await client.files.delete("/tmp/old", recursive=True)
info = await client.files.info("/path/file.txt")
AI Agent
Run AI tasks with structured, typed output.
from pydantic import BaseModel, Field
class ServerHealth(BaseModel):
hostname: str
cpu_percent: float = Field(description="CPU usage percentage")
memory_percent: float
disk_free_gb: float
issues: list[str] = Field(description="List of detected issues")
await client.agent.set_machine("my-server")
result = await client.agent.run(
prompt="Check server health and report any issues",
output_model=ServerHealth,
)
# Typed response - not just text!
health: ServerHealth = result.data
if health.cpu_percent > 90:
alert(f"{health.hostname} CPU critical!")
Skills
Run predefined AI workflows on remote machines. Skills are reusable prompt templates with tool access.
await client.skills.set_machine("my-server")
# List available skills
skills = await client.skills.list()
for skill in skills:
print(f"{skill.name}: {skill.description} ({skill.origin})")
# Inspect a skill
detail = await client.skills.show("code-review")
if detail.found:
print(detail.content) # System prompt markdown
print(detail.source) # File path on machine
# Run a skill
result = await client.skills.run("code-review", "Review the auth module")
print(result.text)
print(f"Took {result.duration_seconds}s, {result.usage.total_tokens} tokens")
Structured output:
from pydantic import BaseModel
class Review(BaseModel):
score: int
summary: str
issues: list[str]
result = await client.skills.run(
"code-review",
"Review the auth module",
output_model=Review,
)
review: Review = result.data
print(f"Score: {review.score}/10")
Custom options:
from cmdop import SkillRunOptions
result = await client.skills.run(
"summarize",
"Summarize the project README",
options=SkillRunOptions(model="openai/gpt-4o", timeout_seconds=120),
)
Download
Download files from URLs via remote server.
from pathlib import Path
async with AsyncCMDOPClient.remote(api_key="cmdop_xxx") as client:
# Set target machine
await client.download.set_machine("my-server")
client.download.configure(api_key="cmdop_xxx")
result = await client.download.url(
url="https://example.com/large-file.zip",
local_path=Path("./large-file.zip"),
)
if result.success:
print(result) # DownloadResult(ok, 139.2MB, 245.3s, 0.6MB/s)
Handles cloud relay limits automatically:
- Small files (≤10MB): Direct chunked transfer
- Large files (>10MB): Split on remote, download parts
SDKBaseModel
Auto-cleaning Pydantic model for scraped data.
from cmdop import SDKBaseModel
class Product(SDKBaseModel):
__base_url__ = "https://shop.com"
name: str = "" # " iPhone 15 \n" → "iPhone 15"
price: int = 0 # "$1,299.00" → 1299
rating: float = 0 # "4.5 stars" → 4.5
url: str = "" # "/p/123" → "https://shop.com/p/123"
products = Product.from_list(raw["items"]) # Auto dedupe + filter
Architecture
┌─────────────┐ gRPC/HTTP2 ┌─────────────┐ gRPC ┌─────────┐
│ Python │◀────────────────▶│ Cloud │◀──────────▶│ Agent │
│ SDK │ Bidirectional │ Relay │ Outbound │ (Go) │
└─────────────┘ └─────────────┘ └─────────┘
Key points:
- Agent makes outbound connection (no port forwarding)
- SDK connects via gRPC (works through any firewall)
- All services multiplexed over single connection
Comparison
| Feature | CMDOP | Tailscale | ngrok | SSH |
|---|---|---|---|---|
| Terminal streaming | gRPC | VPN + SSH | No | Yes |
| File operations | Built-in | SFTP | No | SCP |
| AI agent | Built-in | No | No | No |
| Reusable AI skills | Built-in | No | No | No |
| NAT traversal | Outbound | WireGuard | Outbound | Port forward |
| Client install | None | VPN client | None | SSH client |
| Structured output | Pydantic | No | No | No |
Requirements
- Python 3.10+
- CMDOP agent running locally or API key for remote access
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cmdop-2026.3.5.1.tar.gz.
File metadata
- Download URL: cmdop-2026.3.5.1.tar.gz
- Upload date:
- Size: 203.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
881cf2ed1b41a39fb7c0a2938bd20d52948c8932251a9e40275022cc2af8359d
|
|
| MD5 |
0a85d6381dae30a655777b345f4ace53
|
|
| BLAKE2b-256 |
776005900bd56ffc24372ed09c47addaf94336498d0ff8b7ece11856072ad4af
|
File details
Details for the file cmdop-2026.3.5.1-py3-none-any.whl.
File metadata
- Download URL: cmdop-2026.3.5.1-py3-none-any.whl
- Upload date:
- Size: 341.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27f761a331cc8f962840affb42ed59b36a57d6bdbc155edec8ca4e4d92145709
|
|
| MD5 |
150dd9488a57a7b10833c47ee93a8166
|
|
| BLAKE2b-256 |
a648d2fd8997e5eca06d36dcb71add82eb477b708104c3a77a37ed113342f53f
|