I build platforms that hold up in production: moving fleets to the cloud, turning batch into event streams, and, on my own time, execution platforms and safety tooling for coding agents.
The trace at depth 1, on one axis: education, 7 roles and my own time, with the measured outcomes as span events (◇). The portrait is drawn the way I debug a slow request: runs of the photo become spans as a time cursor sweeps, then drill down, root first, into the photo.
Every span
depth 2 · decision records nest under the role or own timespan · 2016 → now
The same trace, expanded. A role’s children are the decision records I led there; every record shows its result on the row; AC-001 and AC-002 are open. Select any span for its attributes: context, decision, result and the services it touched. The cursor follows your reading, so the waterfall fills in the order it happened.
the spans that lead to a measured outcome: root → role → record → event
root
work (employers unnamed)
own time
education
on the path to a measured outcome
◇ event with a measured outcome
span
Span links the habits that tie spans together across years · drawn as the lanes beside the waterfall
Bars run from mid-year to mid-year: my records give years, not months. Spans that end in 2026 end at the cursor’s “now”.
Replayed at real speed
span AC-010 · gitshift · directory switch
before
3.8 s
v2.1.x
0.5 s
0 s1 s2 s3 s4 s
0.0 s
Text equivalent. Two spans for the same action, switching Git identity when I change directory. Before the change it took about 3.8 s; release v2.1.x of gitshift takes about 0.5 s. The animation runs in real time, so you wait as long as a user did.
Batch window versus event stream
span AC-002 · payment settlement
before · batch on a monolithwaiting for the window
after · streaming with CDCidle
Text equivalent. Ten settlement items arrive during a window (illustrative; the measured rates are about 60% before and 90%+ after). Before, every item waits for one long batch span at the end of the window, with the successful fraction scaled from the reported rate. After, change data capture turns each change into an event, each event gets its own short span as it arrives, with the successful fraction scaled from the reported rate.
Services and attributes
resource attributes on every spanattributes · 2017 → now
In a trace, the services a request touched are attributes on its spans. These are the ones that recur across mine.
Spans without timestamps
real work, no dates in my recordsno timestamp
A trace viewer lists spans it cannot place on the time axis instead of guessing. So do I: these are own-time projects, calls out to other projects, and links to the communities I take part in.
Also built span.kind = internal
Upstream span.kind = client · calls into other projects
Community span links
Continue this trace
propagate the contextnext span · now
Open to senior backend or platform roles, remote or hybrid. Reach me on LinkedIn or GitHub.
root span, resolved: the drill-down ends on the raw photo
Why this design
colophonnot a span · colophon
Concept. Metrics, logs, traces and SLA dashboards run through my production work, so the page reads my career the way I read a slow request: one trace with a root, children, attributes and events, on one honest time axis.
What makes it mine. My name is the root span, a black bar that opens from 2016 to now with the years cut into it; the lanes beside the waterfall are my habits drawn as span links, joining records years apart; and the measured outcomes sit as span events beside the spans that produced them.
Navigation. There is no menu: the header is the trace’s minimap, its cursor follows your reading, the small portrait drills down from spans to my face as you reach now, and every section heading is itself a span on the same axis.
Typography. Fraunces, a soft book face, carries my name and every sentence, because this trace is read as a life rather than an incident; Geist Mono, the instrument, is kept for keys, ids, years and durations.
Colour and motion. Terracotta for work and ochre for own time, the two ends of Gregg’s warm ramp and neighbours of my skin tone, always named in words. Everything moves forward in time: the overview arrives like a request in flight, the gitshift replay runs at real speed, and the portrait plays once and holds.
Accessibility. Every span is a link or a button with its state announced, every animation has a text equivalent beside it, canvases are hidden from assistive technology, reduced motion shows each end state, and “Pause animation” stops everything on the page.
Complete profile
Senior backend & platform engineer · Porto, Portugal
I build platforms that hold up in production: moving fleets to the cloud, turning batch into event streams, and, on my own time, execution platforms and safety tooling for coding agents.
Open to senior backend or platform roles, remote or hybrid
Nine years in production (since 2017)
Decision records
2023–2025 · At work · Platform · Delivered
200+ instances to cloud local zones, with autoscaling
Compute cost fell by ~70% across 200+ instances.
~70% lower compute cost — 200+ instances moved from on-prem and edge sites to cloud local zones, with autoscaling
200+ instances migrated — with autoscaling, for live sporting-event peaks
Context and decision
Context. A real-time platform for live sporting events ran its workloads on on-prem and edge environments.
Decision. Lead the infrastructure modernization: migrate the workloads to cloud local zones and enable autoscaling, with multi-region load tests before peak events.
Stack. Cloud local zones · Autoscaling · Go · Python · Locust
2022–2023 · At work · Payments · Delivered
Payment settlement, from batch to event-driven
Processing success rose from 60% to 90%+.
60% → 90%+ processing success — payment settlement moved from batch to event streams with change data capture
Context and decision
Context. A legacy payment and settlement platform ran as batch processing on a monolith.
Decision. Move the core components to Java and Go, replace batch with streaming and change data capture, containerize on Kubernetes, and centralize logs and dashboards for the SLAs.
Stack. Java · Go · Streaming · CDC · Kubernetes
2026 · Own time · Platform · Working system
Horus: remote execution for builds and agent jobs
A changed worktree is a new job, never a silent retry; a worktree without a data class never leaves the machine.
Context and decision
Context. Builds and coding-agent jobs start on a workstation but need the CPU, isolation and uptime of a remote fleet, without leaking a private worktree or losing work halfway.
Decision. A local daemon with a socket API and a written durability contract; content-hash sync so a job runs on exactly the bytes submitted; recovery bound to that content; a versioned accounting ledger; gVisor sandboxes on VPS runners behind a data-class gate.
Stack. Go · Rust · gVisor
2026 · Own time · Virtualization · Spike
Firecracker microVMs as a sandbox compute driver
A failure-injection suite on a KVM host (kill mid-create, simulated reboot, duplicate RPCs, kill points 0–50 ms, a leak counter) and 23 security probes on a 22-item adversarial matrix. An unimplemented check reports SKIP, never PASS. Proposed upstream as OpenShell#4351.
Context and decision
Context. Can Firecracker microVMs, with the jailer, back an open-source agent sandbox runtime (OpenShell) through the whole lifecycle, and stay correct when things crash?
Decision. A compute driver with its own guest kernel, images from a verified catalog, reclamation of the previous run's VMs at start-up, and a guest flush before Stop.
Stack. Go · Firecracker · KVM
2026 · Own time · Platform design · Accepted
Retire my own agent platform; keep the native clients
Far less to operate; contribution rules now refuse new routers, schedulers and dashboards.
Context and decision
Context. My agent-workflow repository had grown a router, a scheduler, a coordinator hierarchy, a provider dispatcher and a dashboard in front of three coding-agent clients.
Decision. Retire it (19 October 2026). Each client runs natively; the repository keeps shared skills, a small configuration, standalone safety tools and 26 dated decision records.
Stack. Python · Bash
2026 · Own time · Platform safety · Accepted
Safety tools fail closed
Documented as a tripwire, not a sandbox, so nobody mistakes it for isolation.
Context and decision
Context. Coding agents run shell commands in real repositories from three clients with three hook systems; secrets once reached a model through process arguments.
Decision. One command-safety hook for all three clients; output redaction; long-lived credentials kept out of worker reach; a missing safety dependency refuses instead of being caught and allowed.
Stack. Python
2026 · Own time · Distributed systems · Lab
Course labs on microVMs, behind an mTLS control plane
A lab's user id stays reserved until its cleanup has succeeded; CA rotation cannot be bypassed by session resumption.
Context and decision
Context. A course platform gives every learner a disposable lab machine, created and destroyed constantly by many people at once.
Decision. A microVM lab runtime with a chaos test that kills VMs mid-session; idempotent resets by key; mutual TLS on a control-plane CA with reload without restart; pinned keyless signing that fails closed.
Stack. Go · Kotlin · protobuf
2026 · Own time · Storage & consensus · Study
A relational database, from storage to Raft
Built layer by layer as a study; each phase is a commit history.
Context and decision
Context. The fastest way to understand a distributed database is to build its layers in order and see where each guarantee comes from.
Decision. Disk manager, buffer pool, B+ tree, heap file and write-ahead log; SQL parser, planner and Volcano executor; 2PL then MVCC; Raft, Multi-Raft with range sharding, Percolator-style transactions, SSI with hybrid logical clocks, an S3 backend and the PostgreSQL wire protocol.
Stack. Rust
2026 · Own time · Sync & security · Working system
Offline-first sync with signed form-fill
The extension never fills a form the owner did not approve.
Context and decision
Context. A personal job-search tool runs on several desktops plus a browser extension; data must sync without a central source of truth.
Decision. Tombstones pruned only once every active desktop has applied them; fill tokens signed on the desktop with a P-256 key from the OS keyring; an encrypted vault export; an LLM judge measured against blind readings.
Stack. Go · Rust
2025–2026 · Own time · Developer tooling · Shipped v2.1.1
gitshift: many Git identities, one machine
Switching on a directory change went from about 3.8 s to about 0.5 s.
3.8 s → 0.5 s directory switch — gitshift identity switch on directory change, release v2.1.x
Context and decision
Context. Several GitHub and GitLab accounts on one machine means juggling keys, identities and signing by hand.
Decision. One command switches Git author, SSH key, commit signing and the GitHub CLI account, by alias or automatically by directory; releases through GoReleaser and a Homebrew tap.
Load tests to inform cost optimization and Kubernetes autoscaling; graceful shutdown and connection draining in a shared Helm chart; CI repaired with quality gates; codebase rules for agentic coding, shared with the team.
Software engineer, platform / backend
2023–2025 · Real-time platform for live sporting events
Led the move of on-prem and edge workloads to cloud local zones with autoscaling (AC-001); real-time, event-driven services on serverless and containers; Go and Python automation; Locust multi-region load tests for peak events; CI/CD across GoCD, GitHub Actions, Jenkins, Buildkite, Ansible and Packer; metrics, logs, traces and alerts.
Software engineer, payments / settlement
2022–2023 · Payment and settlement platform (consulting)
Led the modernization of a legacy payment and settlement platform to event-driven streaming and CDC (AC-002).
Software engineer, post-purchase
2021–2022 · E-commerce marketplace, several countries
Backend services in Go, Java, Node.js and Groovy for post-purchase and payment workflows; faster claim and dispute resolution.
Software engineer
2019–2021 · Core banking, Brazil
Monoliths and mainframe-based systems modernized into Java and Spring microservices; migration of microservices to the public cloud under regulatory SLAs.
Associate software engineer, CRM & integrations
2018–2019 · Fintech CRM
Real-time CRM features integrated with banking services such as loans, OTP and account management.
Associate software engineer
2017–2018 · Software house
CRM and warehouse management systems in PHP and JavaScript.
How I work
Fail closed: a missing safety dependency refuses; it is never caught and allowed.
Crash and recovery suites before claims: kill mid-create, simulated reboots, leak counters.
Evidence tied to a commit; a check that is not implemented says SKIP, never PASS.
Decision records for every significant choice, including retiring my own platform.
Load tests before peak events.
Also built
Drover
Watch and approve agent sessions from any device: a Rust core over UniFFI, pairing scopes bound to the consumed token.
Rust
JVM performance labs
Eleven on-heap versus off-heap lock-free scenarios with JMH, and 13 serialization frameworks behind one endpoint. Numbers not quoted until re-run with raw output.
Java · JMH
graphql-federation
Federation 2 across Java, Go and TypeScript subgraphs, gRPC between services, SLO burn-rate dashboards.
Java · Go · TypeScript · gRPC
Ponte
A management system for tutoring schools: live lessons with recording and consent, TOTP and lockout, a finance ledger ported to Go and checked by replaying a shared corpus.
TypeScript · Go · PostgreSQL
deep-engineering-knowledge-base
An LLM pipeline that writes and checks engineering lessons, with an independent critic that excludes the author.
Python
techish-visual
An engine for animated technical diagrams: a ThorVG WASM renderer and performance budgets in CI.
TypeScript
keyframe
A Linux studio for recording and editing technical videos, with cuts snapped to silence.
Rust
java-workflows
Reusable GitHub Actions for Java teams: a Java 11 to 25 matrix, security scanning and SBOMs.
GitHub Actions
Upstream
OpenShell#4351
Firecracker compute driver proposal, from AC-004 (open source). · open
OpenShell#4591
A gateway reporting "database is locked" under two concurrent clients. · open
Orca, 10 pull requests
SSH OAuth forwarding, pairing-offer rotation without restart, security events, isolation from external agent config. · 9 open, 1 closed