Inspiration
Security monitoring tools and cyber ranges need believable user activity, but most traffic generators leave obvious fingerprints: a cmd.exe or script interpreter as the parent of every app, and metronome-regular delays. We wanted an agent whose Sysmon and Windows Event Log telemetry looks like a person sat down and did some work.
What it does
Synthetic Colleague runs a ~15-minute "day at the desk" on a Windows VM. Each run performs complete, end-to-end tasks:
- Documents: opens OpenOffice Writer, types a multi-paragraph document with pauses, occasional typos and backspaces, saves it under a plausible filename, and closes it.
- Spreadsheets: opens Calc, builds a small table with per-row formulas and a
SUMfooter, revises a cell, bolds the header, saves as.ods. The saved file is read back and every cell and formula is checked. - Web: opens Chrome, visits several sites, scrolls in bursts with reading pauses, follows a link and comes back, uses find-on-page, saves a page, and closes the browser.
A sequencer shuffles the block order every run, picks a random persona (focused, casual or distracted) that sets the pace, inserts idle gaps and an away-from-keyboard pause, and lands the run on the time budget. No two runs look the same.
How we built it
- Authentic process chains. Apps are launched through the Windows Run dialog (Win+R) driven by
SendInput, so the parent in Sysmon isexplorer.exe. We testedos.startfilefirst, sawpython.exeas the parent, and rejected it. The agent itself starts from a desktop shortcut runningpythonw.exe, so its own parent isexplorer.exetoo. Nosubprocess,Start-Processor Task Scheduler anywhere. - Human timing. Every human-facing delay is sampled from a log-normal distribution with a heavy right tail. Idle gaps are heavy-tailed, and personas scale the pace per run.
- Cold-launch discipline. Each app is fully closed before it is launched again, so every launch produces a fresh
explorer.exe -> appprocess-create event. - Lean by design. Pure Python standard library, no third-party packages, and no LLM in the loop, so the agent adds almost nothing to the VM's CPU and RAM graph.
- Safety net. A
STOPfile halts the run within about a second, known dialogs such as OpenOffice Document Recovery are handled automatically, and a failed block never crashes the run. - Self-validation.
validate.ps1reads the Sysmon log and prints a PASS/FAIL checklist: parent processes, no script or shell parents, cold launches, apps closed at end, run length, timing spread and saved documents.make_histogram.pyproduces a timing report from the run's delays.
Challenges we ran into
- Getting the parent process right. Launch methods that look natural in code (
os.startfile) produced the wrong parent in Sysmon, which pushed us to the Run dialog approach. - Cold-launch behaviour: launching an app that is already open attaches to the existing instance and logs no new process event, so every block closes its app cleanly first.
- OpenOffice quirks: Document Recovery dialogs after a killed run, Calc AutoInput silently completing typed text, and slow cold starts.
- The mock browsing sites had expired certificates for part of the build, and deep links on them sometimes returned 404, so link-click recovery had to behave like a person pressing Back.
Accomplishments that we're proud of
- Validated runs where every Chrome and Writer launch is
explorer.exe-parented and the validator reports PASS. - Runs that land on 900 seconds with all three task types completed and verified on disk.
- An agent whose own overhead is negligible, with the only load on the Proxmox graph coming from the real applications.
What we learned
Process lineage and timing shape are what telemetry actually shows, so effort goes there rather than into per-keystroke polish. Validating against the real Sysmon log, not our own logs, caught problems that unit tests never would.
What's next
Overlapping apps with Alt+Tab, email and download tasks, mixed launch methods (Start search, taskbar), and richer site interaction.
Log in or sign up for Devpost to join the conversation.