Status: Awaiting user sign-off. This is the Phase 1 hard gate per
MASTER.md§5. No production code is written before approval.Lives in
/tmp/xpc-investigation/until Phase 2 creates thenficano/xpcrepo, then moves todocs/ARCHITECTURE.md.Companion documents:
INVESTIGATION.md(Phase 0 findings, command-surface mapping, ARCP-vs-xpctl-gap analysis);protocol/RFC-0001.md(frozen ARCP RFC snapshot — to be created at sign-off time).
| # | Decision | Choice |
|---|---|---|
| D1 | Host CLI language | Go 1.22+ with spf13/cobra + spf13/viper |
| D2 | Agent language / runtime | Python 3.4.10 (already on the VM) |
| D3 | Wire protocol | ARCP envelope shape (RFC 0001), length-prefixed binary framing |
| D4 | Transport | TLS 1.2 over TCP, single port (default 9578) |
| D5 | Authentication | PSK + HMAC-SHA256 message signatures, layered under TLS |
| D6 | Connection model | Stateless v0 (one TCP conn per xpc <cmd>); host-side daemon = Phase 5b |
| D7 | Agent persistence | HKLM Run key (xpctl model); service install deferred |
| D8 | Profile / config | AWS-style split: ~/.xpc/config (non-secret INI) + ~/.xpc/credentials (secret INI) |
| D9 | xpctl compatibility | Fresh xpc serve required. No protocol bridge. xpc migrate-from-xpctl migrates host-side config only |
| D10 | SSH role | Bootstrap + agent lifecycle only. Not a peer transport |
| D11 | Subcommand surface | Sysinternals-flat, mostly top-level; full list in §10 |
| D12 | TLS trust model | Self-signed cert per VM; fingerprint pinned in profile (TOFU on first connect) |
Host (macOS / Linux) XP VM (172.16.20.173)
┌──────────────────────────────┐ ┌────────────────────────────┐
│ xpc (Go binary) │ │ xpc serve (Python 3.4) │
│ ├─ cobra subcommand tree │ │ ├─ ARCP envelope codec │
│ ├─ ARCP envelope codec │ │ ├─ HMAC verify/sign │
│ ├─ HMAC sign/verify │ │ ├─ TLS server (Schannel- │
│ ├─ TLS client (stdlib) │ ───── TLS 1.2 ────► │ │ compatible cipher set)│
│ ├─ profile loader │ ARCP envelopes │ ├─ tool registry │
│ ├─ output formatters │ ◄──── over TCP ───── │ │ (exec/cp/reg/...) │
│ │ (text, json, table) │ length-prefixed │ ├─ persistent state: │
│ └─ stdio output │ │ │ ├─ pyshell consoles │
│ │ │ │ ├─ debugger sessions │
│ │ │ │ └─ active streams │
│ │ │ └─ optional: HKLM Run key │
└──────────────────────────────┘ └────────────────────────────┘
~/.xpc/config (profile defaults, fingerprints) C:\xpc\agent.py
~/.xpc/credentials (PSK secret, profile passwords) C:\xpc\agent.key (PSK)
~/.xpc/state (active profile pointer) C:\xpc\agent.pem (TLS cert)
In v0 there is no xpc daemon process; every xpc <cmd> opens a new TCP connection. Phase 5b adds a host daemon listening on a Unix socket / named pipe to keep one warm TLS connection open.
Why. Single static binary distribution on macOS/Linux/Windows. cobra's subcommand tree, completion generation (xpc completion bash|zsh|fish|pwsh), and --help rendering are battle-tested in kubectl, gh, hugo. Stdlib crypto/tls, net, encoding/json, and goroutines map cleanly onto ARCP's streaming model.
Rejected.
- Rust + clap. Equivalent capability, slower iteration. Rejected on velocity grounds for a daily-use tool.
- Python + click/typer. Fastest dev velocity but distribution is messy (PyInstaller bundles, slow startup,
sys.executableconfusion on Windows). Doesn't match the "AWS CLI v2 / kubectl" target UX fromMASTER.md§2.
Toolchain.
- Go 1.22 minimum.
golangci-lintfor lint (gofmt + vet + staticcheck + revive).go test+testify/requirefor unit tests.goreleaser(or simple Make targets) for darwin-amd64 + darwin-arm64 + linux-amd64 + linux-arm64 release artifacts. Windows host as stretch goal per master prompt §11.9.
Why. Already installed. The existing xpctl agent works today and we are converging the surface area, not rebuilding the runtime. Stdlib-only (socket, ssl, ctypes, subprocess, threading, winreg, code) — no third-party deps, mirroring xpctl's deploy story. The persistent Python REPL (code.InteractiveConsole) is critical for SAPI4/Klatt iteration and is essentially free in Python.
Rejected.
- .NET Framework 4.0 / C#. Better Win32 ergonomics on paper (services, registry, Schannel TLS) but adds cross-build complexity, slower agent-side iteration, and we don't get a payoff for v0 since we're staying with the Run-key persistence model (D7).
- C++ Win32. Smallest deploy, biggest dev cost. No payoff for v0.
Constraints.
- Python 3.4's stdlib
sslsupports TLS 1.2 if the underlying OpenSSL build supports it. The unofficial Python 3.4.10 build for XP currently shipped with xpctl needs to be confirmed in Phase 3 to support TLS 1.2 cipher suites that match modern Go TLS clients. - ctypes against
kernel32/user32/ntdllis XP-32-bit only; we don't have to handle WoW64. - Agent stays a single
agent.pyfile, deployed alongsideagent.keyandagent.pem.
Why. ARCP closes every protocol-level gap xpctl has today: streaming exec output (stream.chunk), cancellation (cancel), durable file pulls (job.checkpoint + resume), tracing across multi-step workflows (trace_id, span_id, causation_id), permission challenges for state-changing ops (permission.request/grant with lease_id), and at-least-once delivery via dedupe-by-id. xpctl's wire shape is already very close ({id, type, action, params, status, data, error}) — adopting ARCP is closing the gaps, not rewriting from scratch.
Envelope shape used by xpc (subset of RFC §6.1):
{
"arcp": "1.0",
"id": "msg_01HABCDEF", // ULID; idempotency key
"type": "tool.invoke", // see message types below
"session_id": "sess_01HSE...", // assigned at session.open
"job_id": "job_01H...", // present after job.accepted
"stream_id": "str_01H...", // present for stream.* messages
"trace_id": "tr_01H...", // stable across one xpc <cmd>
"span_id": "sp_01H...",
"correlation_id":"msg_01H...", // command id this responds to
"causation_id": "msg_01H...",
"timestamp": "2026-05-08T18:21:00Z",
"auth": {"alg":"HMAC-SHA256","kid":"v0","sig":"..."},
"payload": { /* type-specific */ }
}Message types in v0 (subset of RFC §6.2):
- Control:
session.open,session.accepted,session.close,ping,pong,ack,nack,cancel,permission.request,permission.grant,permission.deny. Deferred:resume,checkpoint.create/restore,backpressure. Adding these is non-breaking later. - Execution:
tool.invoke,tool.result,tool.error,job.accepted,job.started,job.progress,job.completed,job.failed,job.cancelled. Deferred:job.heartbeat,job.checkpoint,workflow.start,agent.delegate,agent.handoff. - Streaming:
stream.open,stream.chunk,stream.close,stream.error. All in v0. - Event:
logonly. Deferred:metric,trace.span— OTel export designed in RFC 0002.
Capability negotiation at session.open:
{ "capabilities": {
"streaming": true,
"durable_jobs": false, // v0 has no durable storage
"checkpoints": false, // deferred
"binary_streams": true, // for cp / dump / shot
"agent_handoff": false
}}Rejected.
- xpctl-style request/response. Re-inventing what ARCP already specifies; no path to MCP integration; would have to retrofit streaming/cancellation later. Master prompt's emphasis on "uniform UX across every subcommand" is satisfied better by a single ARCP-shaped contract.
- gRPC. Effectively dead on XP —
grpcioPython wheels don't exist for 3.4, and modern .NET gRPC is XP-incompatible. - JSON-RPC 2.0. Subset of what ARCP gives. Choosing it would mean re-implementing most ARCP semantics on top of it.
Why. Same framing as xpctl today ([4-byte BE uint32 length][UTF-8 JSON payload]), wrapped in TLS. This deviates from ARCP RFC §17 mandatory transports (WebSocket, stdio); we're trading conformance for pragmatism on XP.
Framing details.
- Outer:
[4-byte BE uint32 length][payload bytes].length ≤ 50 MB(matching xpctl's safety limit). - Inner: UTF-8 JSON envelope (D3). Binary streams (
stream.chunkfor cp/dump/shot) embed bytes as base64 in payload; alternative to evaluate in Phase 3: a second framing channel for binary blobs that bypasses base64 (saves 33%). Decide in Phase 3 spec, not here. - Per-connection: TLS 1.2 handshake → optional
session.openexchange → message stream until either side sendssession.closeor the TCP closes.
TLS configuration.
- Cipher suites:
ECDHE-RSA-AES256-GCM-SHA384,ECDHE-RSA-AES128-GCM-SHA256minimum. To be confirmed against XP's Python 3.4 OpenSSL build in Phase 3. - Cert: self-signed, generated at
xpc bootstrapon the VM, fingerprint pinned in~/.xpc/configper profile. First connection prompts TOFU. No CA. No SAN-based hostname verification (we use IP-rooted fingerprint pinning). - The Go client uses
tls.Config{InsecureSkipVerify: true, VerifyConnection: pinFingerprint}. The XP Python server usesssl.SSLContext(ssl.PROTOCOL_TLS_SERVER).
Rejected.
- WebSocket over TLS. Strictly conformant with ARCP RFC §17. Requires a WS library that runs on Python 3.4 on XP (e.g.
websockets-port or hand-rolled). Defer until v2; gives us a path to plug into MCP/browser tooling later without changing message shape. - Cleartext TCP (xpctl current). Rejected: ARCP envelope already includes
auth.sig, but without TLS the wire is replayable/snoopable. PSK alone over cleartext leaks message contents; we want both.
Why. Provisioning a per-VM 32-byte secret is trivial at xpc bootstrap; PKI/mTLS would require a CA story that's too much friction for v0. HMAC on every message gives replay-protection (id + monotonic timestamp), key-rotation hooks (auth.kid field for future rotation), and a clear authorization boundary at the agent.
Mechanism.
xpc bootstrapgenerates a 32-byte random secret. Stores host-side aspskin~/.xpc/credentialsunder[<profile>]. Stores VM-side asC:\xpc\agent.key(file ACL set so only the running user can read).- Every envelope carries
auth: {alg: "HMAC-SHA256", kid: "v0", sig: hex(hmac(psk, canonical_envelope_minus_auth))}. Canonicalization spec: deterministic JSON serialization (sorted keys, no extra whitespace) of the envelope minusauth.sig. - Agent verifies HMAC before dispatching. Mismatched
kidor bad sig →nackwithauth_failedand connection close. session.openrejected without valid HMAC → no message dispatch.
Rotation (deferred).
xpc rotate-key: generate new secret, push to agent under a newkid(v1), let agent accept both for an overlap window, then retirev0. Implement in Phase 6+.
Rejected.
- mTLS with self-signed certs. Conceptually clean but more code, more failure modes (cert expiry, regen on VM rebuild, file-ACL handling on XP). No payoff vs. PSK on a private LAN.
- Both layered (mTLS + HMAC). Defensible but excessive for v0. PSK + TLS gets us replay protection, confidentiality, and authorization with one moving part.
- No auth. Present xpctl model. Re-touching the protocol later costs more than doing it once now.
Why. Master prompt §5 recommends a daemon for latency reasons but allows it to be deferred. Phase 5 critical-path (first working xpc exec dir C:\) is shorter without the daemon. ~5 ms LAN latency means a stateless model is acceptable; users running tight loops will appreciate the daemon when we add it.
v0 contract. Each xpc <cmd> invocation:
- Loads profile from
~/.xpc/configand credentials from~/.xpc/credentials. - Opens a TLS connection to
<host>:<port>. - Sends
session.open(with capability negotiation). - Sends one or more
tool.invoke(or other commands) per the subcommand. - Streams output via
stream.chunkto local stdout/stderr; collects terminaltool.result/job.completed/tool.error. - Sends
session.close, drops the TCP connection. - Returns the exit code.
Phase 5b daemon. A long-lived host process (xpc daemon) listening on ~/.xpc/run/daemon.sock. CLI invocations connect via the socket; daemon multiplexes their requests onto one warm TLS connection per profile. Backwards compatible: if the daemon isn't running, the CLI falls back to direct connect.
Rejected.
- Daemon required from Phase 5. Pushes "first working subcommand" later. Adds Phase 5 risk for no Phase-5 payoff.
- Skip the daemon entirely. Tight loops over the LAN suffer; future MCP-style scenarios need persistent context.
Why. xpctl uses this today and it works. Service install on XP is finicky and adds debug surface in Phase 4. Run key is sufficient because the VM is single-user and is left logged in (typical RE/automation lab setup).
Mechanism (mirrors xpctl).
- Registry value:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run\xpc_agent="C:\Python34\python.exe" "C:\xpc\agent.py" --port 9578. xpc serve install-startup/remove-startup/startup-status— direct port of xpctl's actions.- Service install (
xpc serve install --as-service) is a Phase 6+ option, not v0.
Rejected for v0. Service install (more work, no payoff). Both modes (more code paths to test).
Layout.
~/.xpc/
├── config # non-secret INI: hosts, ports, transport flags, fingerprints
├── credentials # secret INI: PSK secrets, optional SSH passwords
├── state # active profile pointer (single line, just the profile name)
└── run/ # Phase 5b: daemon socket + pid file
~/.xpc/config schema (per profile):
[profile lab]
host = xp-truvoice-w02
port = 9578
fingerprint = sha256:AB:CD:... # pinned at first connect
proxmox_host = # optional, for xpc snap
proxmox_user = # optional
ssh_user = cyg_server # used only by xpc bootstrap and xpc serve lifecycle
verify_host_key = true~/.xpc/credentials schema (per profile):
[profile lab]
psk = base64-encoded 32-byte secret
ssh_password = ... # optional, only if PSK-based SSH not configured~/.xpc/state:
default
xpc configure behavior:
- Aws-style interactive prompts for host/port/ssh_user.
- Validates connection via TLS handshake +
ping. - If cert is unknown: TOFU prompt (display fingerprint, ask Y/n to pin).
- Writes both files with
0o700/0o600perms.
xpc migrate-from-xpctl behavior:
- Reads
~/.xpcli/config. For each[<name>], write[profile <name>]to~/.xpc/config(withhost,port,ssh_user,verify_host_key) and[profile <name>]to~/.xpc/credentials(withssh_password). Does not generate PSK; user runsxpc bootstrap <profile>to deploy a new agent and key.
Env vars (mirroring xpctl): XPC_PROFILE, XPC_HOST, XPC_PORT, XPC_SSH_USER, XPC_SSH_PASSWORD. Override config file values; credentials file values take precedence over env-var passwords (so secrets aren't accidentally exposed via shell history).
Implication. No protocol bridge. The xpc protocol library has one parser. The legacy xpctl agent on the VM is replaced during xpc bootstrap. xpc migrate-from-xpctl only handles host-side config — VM-side state is replaced.
Migration UX. xpc bootstrap <profile>:
- Connects via SSH (using migrated profile credentials).
- Stops the xpctl agent (graceful via TCP
agent_shutdown, fall back to WMIC kill via SSH). - Removes
C:\xpctl\(optional, behind a confirmation flag). - Deploys
agent.py,agent.key(newly generated PSK),agent.pem(newly generated TLS cert) toC:\xpc\. - Registers
xpc_agentin HKLM Run key. - Starts the agent.
- Waits for ARCP
pingto succeed. - Persists fingerprint into
~/.xpc/config.
Why. The agent is the canonical control plane for v0. SSH exists for:
- First-boot bootstrap when no agent is yet deployed.
- Agent lifecycle: start/stop/redeploy when the agent is dead or being upgraded.
- Recovery when the agent is wedged.
For day-to-day commands (exec, cp, reg, ps, etc.), the protocol library refuses to send over SSH — there's no SSH transport in the agent code path. This drops a large quantity of ssh_support glue from the codebase.
Mechanism. The host-side SSH path uses the local ssh binary with paramiko as a fallback (matching xpctl's robustness). Subset of operations: file push/pull (via SCP), remote command exec (cmd.exe), starting/killing the agent process. Implemented in the Go host as a thin internal/sshlife package, used only by xpc bootstrap and xpc serve {install,start,stop,redeploy}.
See §10 for the full locked surface. Sysinternals-flat: short top-level commands rather than deep groups. Exceptions: xpc agent <op> (lifecycle), xpc reg <op>, xpc bat <op>, xpc py <op>, xpc snap <op>, xpc dbg <op>, xpc trace <op>, xpc dll <op>, xpc gui <op>, xpc svc <op>, xpc net <op>, xpc evt <op> — each because the subcommand has clearly-related operations that benefit from grouping. Everything else is top-level.
Why. No CA infrastructure on a personal LAN. xpc bootstrap generates a self-signed cert on the VM. First xpc <cmd> against a profile compares the cert against the pinned fingerprint in the profile; if absent, TOFU prompt; if present and mismatching, refuse and surface the change.
Cert rotation uses the same prompt: xpc bootstrap --regenerate-cert regenerates and re-pins.
xpc exec dir 'C:\'
│
├── 1. Load profile 'default' from ~/.xpc/config and ~/.xpc/credentials
├── 2. Open TCP/TLS to xp-truvoice-w02:9578
├── 3. Verify TLS cert fingerprint against pinned value in profile
├── 4. session.open { capabilities: {streaming, binary_streams} } [HMAC signed]
│ ◄── session.accepted { session_id, agent.capabilities }
├── 5. tool.invoke { tool: "exec", arguments: {cmd: "dir C:\\", shell: "cmd"} } [HMAC]
│ ◄── job.accepted { job_id, correlation_id }
│ ◄── job.started { job_id }
│ ◄── stream.open { stream_id, content_type: "text/plain", channel: "stdout" }
│ ◄── stream.chunk { stream_id, delta: "Volume in drive C is..." }
│ ◄── stream.chunk { ... }
│ ◄── stream.close { stream_id }
│ ◄── tool.result { exit_code: 0 } | tool.error { code, message }
│ ◄── job.completed { state: "completed" }
├── 6. session.close
└── 7. Return exit code 0 to shell
This becomes the Phase 5 exit-gate test, run against the real VM.
| Phase | Exit condition |
|---|---|
| 0 | INVESTIGATION.md complete; user signed off on §10 answers. ✅ |
| 1 | This doc signed off. ⏳ |
| 2 | nficano/xpc private repo exists; TASKS.md populated from MASTER.md + this doc; CI green on scaffold; branch protection on |
| 3 | Real-network ARCP round-trip passes against the XP VM (host stub ↔ agent stub) |
| 4 | xpc serve deployable + installable as Run-key startup; test client gets dir C:\ output back |
| 5 | xpc exec dir 'C:\' end-to-end against real VM; bash + zsh completion work; xpc configure works |
| 5b (optional) | xpc daemon warm-connection multiplex working |
| 6+ | Per subcommand: unit + integration + real-VM tests green, PR merged, TASKS.md + CHANGELOG updated |
| # | Risk | Likelihood | Mitigation |
|---|---|---|---|
| R1 | Python 3.4 OpenSSL doesn't support TLS 1.2 with cipher suites Go expects | Medium | Phase 3 includes a real-VM TLS handshake test; fallback to TLS 1.0 with HMAC carrying the security if needed |
| R2 | ARCP RFC drifts during construction | Medium | Snapshot RFC at architecture sign-off into docs/protocol/RFC-0001.md; treat as immutable for v0 |
| R3 | Bootstrap mirror (Cygwin 2016 snapshot) goes offline | Low | Bundle cygwin-2.874.exe in repo; host installer assets in installs/ like xpctl does |
| R4 | XP VM rebuild loses pinned fingerprint and PSK; xpc <cmd> fails opaque |
Low | xpc bootstrap --regenerate regenerates both; document recovery in CONTRIBUTING |
| R5 | base64-in-JSON is too slow / memory-heavy for large xpc dump (process minidump) pulls |
Medium | Phase 3 evaluates a binary-channel framing alternative; if slow, add it before xpc dump lands |
| R6 | Run-key persistence loses agent on RDP/VNC disconnect | Low (existing xpctl behavior) | Future: service-install mode behind --as-service flag |
| R7 | Stateless v0 connection setup latency hurts in tight loops | Low | Phase 5b daemon resolves it; v0 acceptable on LAN (~10 ms TLS handshake) |
| R8 | XP-side Python 3.4's ssl module doesn't support verify_mode=CERT_NONE + cert validation we need |
Medium | Phase 3 spike confirms; alternative is HMAC-only on cleartext + pinned IP if TLS proves intractable (we'd downgrade D4) |
| R9 | Cobra completion script for fish/pwsh has known rough edges | Low | Ship bash + zsh first; fish/pwsh as best-effort with documented gaps |
| R10 | Sub-agent dispatch in Phase 6+ creates merge conflicts on shared infra | Medium | Phases 1-5 stay sequential; sub-agent dispatch only after the protocol & daemon are frozen |
xpc/
├── MASTER.md # the master prompt, verbatim
├── README.md
├── CHANGELOG.md
├── LICENSE # MIT (matching xpctl)
├── CONTRIBUTING.md
├── SECURITY.md
├── TASKS.md # source of truth, populated in Phase 2
├── go.mod
├── go.sum
├── Makefile
├── .github/workflows/
│ ├── ci.yml # lint + test on PR
│ ├── release.yml # tag-driven goreleaser
│ └── real-vm-test.yml # manual dispatch only
├── .pre-commit-config.yaml
├── docs/
│ ├── INVESTIGATION.md # moved from /tmp/xpc-investigation/
│ ├── ARCHITECTURE.md # this doc
│ ├── PROTOCOL.md # written in Phase 3
│ ├── protocol/
│ │ └── RFC-0001.md # frozen ARCP snapshot
│ ├── SPEC-<subcommand>.md # one per subcommand starting Phase 6
│ └── sessions/ # real-VM session logs
├── cmd/
│ └── xpc/ # main package (host CLI binary)
├── internal/
│ ├── arcp/ # envelope codec, message types, HMAC, capability negotiation
│ ├── transport/ # TLS+TCP framing
│ ├── profile/ # ~/.xpc/{config,credentials,state}
│ ├── output/ # text|table|json formatters
│ ├── sshlife/ # SSH lifecycle helpers (bootstrap, install, kill)
│ └── cli/ # cobra commands, one file per subcommand
├── agent/
│ ├── agent.py # the on-VM agent (single file, Python 3.4-compatible)
│ ├── tests/ # python tests for agent dispatch + protocol roundtrip
│ └── scripts/ # helper python scripts the agent uses (mem_read, dll_inject, etc.)
├── installs/ # bundled Python/Cygwin/OllyDbg/x64dbg archives (mirrors xpctl)
└── tests/
├── integration/ # mock-agent-in-process integration tests
└── real_vm/ # real-VM test fixtures (manual workflow only)
Per MASTER.md §12: three layers, all required.
- Unit (Go + Python). Pure-function tests on envelope encode/decode, HMAC, profile loading, output formatters. Property-based tests via
gopter(Go) andhypothesis(Python) on the wire format roundtrip. - Integration. A mock agent (Python
agent.pyrunning in a subprocess on the host CI) talking to the Go CLI over a Unix socket /localhost:0. Fast, deterministic, runs on every PR. - Real-VM. A manually-triggered CI workflow plus a
make test-real-vmtarget that points at the live VM in~/.xpc/config. Required green before tagging a release; not required on every PR.
CI on PR: lint + unit + integration. CI on tag push: above plus release artifacts. Manual real-vm-test.yml workflow: any time, gated by approval.
Not blockers for Phase 1 sign-off.
- Proxmox API host + auth for
xpc snap— gathered when Phase 6+ implements the subcommand. - PSK rotation UX (
xpc rotate-key) — Phase 6+. - WebSocket transport — possible v2 if MCP integration becomes interesting.
- Service install (
xpc serve install --as-service) — Phase 6+. - OpenTelemetry export — designed in RFC 0002 (host-side OTLP producer).
xpc daemonhost-side multiplex — Phase 5b.- Argv[0]-based shims (
xpcexec,xpcreg) — after dispatcher is solid. - Binary-channel framing alternative to base64-in-JSON for big binary streams — evaluated in Phase 3.
Top-level (Sysinternals-flat). Items marked "extra" are preserved from xpctl and renamed per Phase 0 §11.1.
# Setup / lifecycle
xpc configure # interactive profile setup
xpc bootstrap [<profile>] # first-boot deploy of agent + key + cert
xpc migrate-from-xpctl # one-shot migration of ~/.xpcli/config
xpc completion bash|zsh|fish|pwsh
xpc rotate-key # deferred to Phase 6+
xpc profile list|add|remove|use
xpc use <profile>
# Agent lifecycle
xpc serve [--port N] # the agent itself; runs on the XP VM
xpc serve install-startup|remove-startup|startup-status
xpc agent ping|status|info
xpc agent deploy|start|stop|redeploy
xpc agent install|uninstall # full install: deploy + start + register
xpc daemon # Phase 5b
# Core remoting
xpc exec <cmd> [args...] # streaming stdout/stderr/exit
xpc cp <src> <dst> # bidirectional, host:/vm: prefixes
xpc bat run|push-run|create
xpc reg get|set|delete|export
xpc py run|repl|pip|local # `local` is the renamed `xpctl script`
xpc tun -L|-R port:host:port # ARCP-multiplexed tunnels
# System / info
xpc info # systeminfo
xpc ps
xpc net netstat|ipconfig|route # `xpc net` summary if no subcommand
xpc svc list|start|stop|install|uninstall|status
xpc env list|set
xpc evt tail|query
xpc boot reboot|shutdown|pause|resume
# RE-focused
xpc dll list|inject|regsvr32
xpc dump <pid> [--full]
xpc inj <pid> <dll> # alias of `xpc dll inject`
xpc shot # gui screenshot
xpc send keys|click|move
xpc gui window-list # remaining GUI helper
xpc dbg attach|run|server # OllyDbg / WinDbg(CDB) / x64dbg
xpc trace start|stop|pull
xpc ghidra start|stop
xpc ida start|stop
xpc snap list|create|restore|delete
# Filesystem / coreutils-flavored extras (preserved from xpctl, renamed)
xpc cat <vm:path>
xpc head <vm:path>
xpc tail <vm:path>
xpc find <vm:path>
xpc sum <vm:path>
xpc fetch <url> [vm:path] # download URL → upload to VM
xpc edit <vm:path> # download → $EDITOR → re-upload
xpc watch <cmd> # repeat cmd at interval
Universal flags (per MASTER.md §11): --profile, --target, --output {text|table|json}, --dry-run (state-changing only), -v/--verbose, --timeout. Exit codes: 0 ok, 1 generic, 2 usage, 3 connection, 4 auth, 5 remote command (with remote exit propagated where sensible).
Phase 1 closes when the user confirms each row.
- D1 Go + cobra
- D2 Python 3.4 agent
- D3 ARCP envelopes
- D4 TLS-TCP, length-prefixed binary framing
- D5 PSK + HMAC-SHA256
- D6 Stateless v0, daemon Phase 5b
- D7 HKLM Run key persistence
- D8
~/.xpc/{config,credentials,state}AWS-style split - D9 Fresh
xpc serve; no compat bridge - D10 SSH only for bootstrap + lifecycle
- D11 Subcommand surface in §10
- D12 Self-signed TLS + TOFU + fingerprint pinning
- §6 Risks acknowledged
- §10 surface acceptable; nothing to add or remove
- Repo skeleton in §7 acceptable
When approved, I will:
- Create
nficano/xpcprivate GitHub repo (Phase 2). - Move INVESTIGATION.md and ARCHITECTURE.md from scratch into
docs/. - Commit
MASTER.mdat repo root. - Snapshot the current ARCP RFC text into
docs/protocol/RFC-0001.md. - Populate
TASKS.mdfrom this doc +MASTER.md. - Configure CI and branch protection.
- Hand control back for Phase 3 (wire protocol foundation).