Claude (noether) 940c3525ef sicd: port the wire protocol to the Go daemon (cmd/sicd)
The Go daemon is what actually runs on 30+ fleet hosts; until now it had none of the
wire-protocol work that went into the Python reference (gateway/sicd) — which is why sic
still ate a bare -- and silently wrote zero-byte files in production. This ports it: preamble
+ nested netstring peeling (one layer per hop), payload -> child stdin then remaining stdin
pumped through (the zero-byte-file fix), bare -- survives as opaque payload, malformed frame
-> exit 1, no deadlock above the 64 KiB pipe buffer, short writes looped, EPIPE handled,
signal-killed child -> exit 128+WTERMSIG. Built by the bullpen room (@testdesigner -> @godev
-> @reviewer), the first Go work the room could grade.

CHECKPOINT commit, green but NOT final: 28/28 Go, 24/24 Python, go vet clean. @reviewer's
third pass found four divergences from the reference that a fix round is about to address —
recorded here so the checkpoint is honest:
  1. (must-fix, security) the Go netstring parser accepts frames the reference REJECTS and
     executes them: trailing data after the comma, a +-prefixed length, and no 1<<24 cap. A
     malformed frame that fails closed on a Python hop currently runs on a Go hop. The Python
     suite does not pin these either — both suites need the malformed cases added.
  2. (must-fix) the read-error path os.Exit(1)s without reaping the child, leaving it detached
     and still writing to inherited stdout after sicd reports its status.
  3. (test) an EPIPE test's premise is wrong in Go (LookPath fails at Start, so the payload
     write never happens); the path is really covered by the signal test.
  4. (test) the pty EIO test is synchronized only by a 300 ms sleep.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 05:37:53 +02:00

sic

Run a command on a remote host without a shell re-parsing its arguments.

ssh host touch 'a b' creates two files: ssh joins its arguments with spaces and hands the result to the remote login shell, which splits it again. sic host touch 'a b' creates one file named a b. sic sends the argument vector to a daemon on the host as length-prefixed fields, and the daemon calls execvp on it. No shell parses the arguments.

Components

  • sic — client. Takes argv on the command line, frames it as netstrings, pipes the frame over ssh to sicd.
  • sicd — daemon on the target host. Reads netstrings from stdin and runs the command.

Both are single static Go binaries (cmd/sic, cmd/sicd). A Python reference implementation of the daemon is in gateway/sicd.

Wire format

Each field is a netstring: <length>:<bytes>,. A frame is a mode field, zero or more argument fields, and an empty terminator:

<mode> <arg>* 0:,

argv = ["touch", "a b"] is 4:exec,5:touch,3:a b,0:,. The length prefix means no byte needs escaping and no delimiter can collide with the payload.

mode selector behaviour
exec (default) 4:exec, execvp(argv), no shell. Arguments are passed through unchanged.
sh 2:sh, one field passed to sh -c. Pipes, redirects, and globs work.

Usage

sic <host> <command> [arg ...]
sic --sh <host> '<shell string>'
sic <host> -- <command> [arg ...]      # explicit separator
sic host1 echo hello world
sic host1 touch 'a b'                # one file named "a b"
sic host1 echo '$HOME'               # literal, no expansion
sic --sh host1 'echo hi | wc -c'

Build

go build -o bin/sic  ./cmd/sic
go build -o bin/sicd ./cmd/sicd

Install

Client:

cp bin/sic ~/bin/sic

Daemon on each target host. sicd runs what it is sent, so it must only be reachable over an authenticated transport. Pin it to a dedicated ssh key so the target can run nothing else with that key:

scp bin/sicd host:/tmp/sicd
ssh host 'sudo install -m755 /tmp/sicd /usr/local/bin/sicd'
# ~/.ssh/authorized_keys on the target:
# command="sicd",no-port-forwarding,no-pty ssh-ed25519 AAAA...

Do not listen on a TCP or message-bus port.

Test

printf '4:exec,2:id,0:,' | ssh host sicd
sic host echo hello world

See also

  • docs/design.md — wire format, exec modes, transport and security, prior art.
  • demos/quoting-hell.py — six cases run both ways, plain ssh versus sic.
  • SKILL.md, SKILL-bg.md — agent skill definitions (foreground and background).
S
Description
Quoting-proof remote command execution: netstrings + execvp over ssh.
Readme MIT 3.4 MiB
Languages
Go 71%
Python 23.4%
Shell 5.6%