Human Typing Mode Plan
#Goals
- Give
peekaboo typeand the MCPtypetool a first-class--wpm/wpmknob so automation can mimic fast but believable humans without guessing raw millisecond delays. - Ensure every caller (CLI, ProcessService, agents) travels through a shared
TypingCadencemodel so future heuristics (thinking pauses, typo injection) slot in without new flags. - Keep deterministic fallbacks (
--delay, JSON output) so scripted runs and regression tests stay repeatable when human cadence is disabled.
#Reference Behavior
#Words-per-minute baseline
“Words per minute” is standardized at five characters per word, so base inter-key delay (ms) = 60_000 / (wpm * 5). Example: 150 WPM ≈ 80 ms per key before jitter.citeturn0search11
#Realistic jitter curves
Keystroke flight and dwell times follow skewed, log-normal-style distributions rather than uniform noise, so our sampler should pull delays from a log-normal (or log-logistic) curve, then clamp to reasonable bounds. This matches research showing keyboard dynamics contain multiple overlapping log-normal components.citeturn0search5
#Inspiration from existing tools
The human-keyboard automation library exposes knobs for WPM, “thinking delay”, space/punctuation multipliers, and optional typo correction—concrete precedents we can mirror (minus the typo bits for now) so our UX feels familiar.citeturn1search7
#Parameter Mapping
| Mode | Approx. WPM | Base delay (ms) before jitter | Notes |
|---|---|---|---|
--wpm 120 (default) | 120 | ~100 | Feels like a fast typist, safe for demos. |
--wpm 150 | 150 | ~80 | “Pro” speed; cap jitter so bursts stay under 120 ms. |
--wpm 90 | 90 | ~133 | Safer for flows that must look cautious/human. |
Implementation: derive base delay from the formula, then apply ±20 % jitter per character, add +35 % before whitespace/punctuation, and insert a 300–500 ms “thinking pause” every N (default 12) words. Future flags can expose jitter magnitude once core behavior ships.
#Implementation Plan
#CLI & Commander layer
- Surface
--profile human|linearso WPM is only relevant when profile == human, with human as the default profile. Linear continues to honor--delayfor deterministic pacing. - Add
@Option(name: .customLong("wpm"), help: ...) var wpm: Int?toTypeCommand, treating it as mutually exclusive with--delaywhen--profile linearis selected. - Validate acceptable range (80–220) and warn when users mix both knobs (“WPM takes precedence over --delay”).
- Emit the chosen cadence inside
TypeCommandResultso downstream log parsing shows whether human mode was active.
#Shared cadence model
- Introduce
TypingCadencein PeekabooFoundation:.fixed(milliseconds: Int)and.human(wordsPerMinute: Int). - Extend
TypeActionsRequest,AutomationServiceBridge.typeActions, andUIAutomationServiceProtocolto pass the cadence instead of a baretypingDelay. - Mirror the new schema in the MCP
typetool (profile,wpm,delay), giving precedence rules identical to the CLI.
#TypeService algorithm
- When cadence ==
.human, compute the base delay from WPM, then: - Sample per-character wait times via a log-normal generator seeded by
TypingCadenceSamplerso tests can inject deterministic values. - Multiply waits by 1.35 for spaces/punctuation and divide by 1.15 for alphanumeric digraphs to create bursts.
- Every N words, insert a “thinking pause” (configurable default 350 ms) before resuming normal jitter.
- Fall back to the existing fixed-delay loop when cadence ==
.fixedto keep legacy scripts untouched. - Emit the resolved
TypingCadencetoVisualizationClient.showTypingFeedbackso the Peekaboo.app typing widget mirrors the exact human/linear profile and WPM being used.
#Testing & Observability
- CLI tests: ensure parsing enforces mutual exclusivity, default WPM, and JSON serialization.
- TypeService tests: supply a fake sampler to assert the produced delays stay within ±20 % of the base and honor punctuation multipliers.
- Logging: add a single debug line (“human typing @ 150 WPM, jitter ±20 %”) so diagnosing cadence mismatches is trivial without verbose tracing.
#Future Extensions
- Once stable, consider exposing optional typo/backspace injection and variance sliders, modeled after the knobs that
human-keyboardsurfaces today.citeturn1search7 - Add a
--thinking-pause-msoverride for workflows that need deterministic pauses (e.g., compliance demos) without toggling the entire cadence engine.