RepoPilotOpen in app →

TimelyDataflow/timely-dataflow

A modular implementation of timely dataflow in Rust

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1w ago
  • 4 active contributors
  • MIT licensed
Show all 7 evidence items →
  • CI configured
  • Tests present
  • Small team — 4 contributors active in recent commits
  • Concentrated ownership — top contributor handles 59% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/timelydataflow/timely-dataflow)](https://repopilot.app/r/timelydataflow/timely-dataflow)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/timelydataflow/timely-dataflow on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: TimelyDataflow/timely-dataflow

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/TimelyDataflow/timely-dataflow shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 1w ago
  • 4 active contributors
  • MIT licensed
  • CI configured
  • Tests present
  • ⚠ Small team — 4 contributors active in recent commits
  • ⚠ Concentrated ownership — top contributor handles 59% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live TimelyDataflow/timely-dataflow repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/TimelyDataflow/timely-dataflow.

What it runs against: a local clone of TimelyDataflow/timely-dataflow — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in TimelyDataflow/timely-dataflow | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 37 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>TimelyDataflow/timely-dataflow</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of TimelyDataflow/timely-dataflow. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/TimelyDataflow/timely-dataflow.git
#   cd timely-dataflow
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of TimelyDataflow/timely-dataflow and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "TimelyDataflow/timely-dataflow(\\.git)?\\b" \\
  && ok "origin remote is TimelyDataflow/timely-dataflow" \\
  || miss "origin remote is not TimelyDataflow/timely-dataflow (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "timely/Cargo.toml" \\
  && ok "timely/Cargo.toml" \\
  || miss "missing critical file: timely/Cargo.toml"
test -f "communication/src/lib.rs" \\
  && ok "communication/src/lib.rs" \\
  || miss "missing critical file: communication/src/lib.rs"
test -f "timely/examples/hello.rs" \\
  && ok "timely/examples/hello.rs" \\
  || miss "missing critical file: timely/examples/hello.rs"
test -f "communication/src/allocator/mod.rs" \\
  && ok "communication/src/allocator/mod.rs" \\
  || miss "missing critical file: communication/src/allocator/mod.rs"
test -f "mdbook/src/SUMMARY.md" \\
  && ok "mdbook/src/SUMMARY.md" \\
  || miss "missing critical file: mdbook/src/SUMMARY.md"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 37 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~7d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/TimelyDataflow/timely-dataflow"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Timely Dataflow is a low-latency cyclic dataflow computational model implemented in Rust that enables the same program to scale from a single thread on a laptop to distributed execution across a cluster. It provides expressive data-parallel computation with high performance through a modular architecture spanning five core crates (bytes, communication, container, logging, timely) that handle memory management, inter-process communication, data containers, event logging, and the dataflow runtime itself. Workspace monorepo with six semi-independent crates: (1) bytes/ for byte-level utilities, (2) communication/ handles inter-worker transport (thread, process, zero-copy TCP allocators in communication/src/allocator/), (3) container/ provides data container abstractions, (4) logging/ implements event tracing, (5) timely/ is the core dataflow engine with operators, and (6) mdbook/ for documentation. Examples live in timely/examples/ (simple.rs, hello.rs demonstrate the API surface).

👥Who it's for

Data engineers and researchers building distributed streaming systems, graph processing engines, or incremental computation frameworks who need deterministic, low-latency execution with support for cyclic dependencies and iterative algorithms. Contributors are typically systems programmers and database/distributed-systems researchers familiar with Rust and dataflow concepts.

🌱Maturity & risk

Production-ready and actively maintained. The project has comprehensive CI/CD via GitHub Actions (test.yml, miri.yml, release-plz.yml), follows semantic versioning with a CHANGELOG.md, enforces Rust 1.86+ stability, and maintains detailed documentation at docs.rs. Recent activity includes automated dependency management (dependabot.yml) and regular releases, indicating sustained development and community support.

Low-to-moderate risk. The codebase is large (~812k lines of Rust) with a multi-crate architecture requiring careful coordination across workspace dependencies (bytes/, communication/, container/, logging/, timely/). Key risks: the networking/communication layer (communication/src/allocator/zero_copy/tcp.rs, etc.) handles complex unsafe code patterns; distributed system semantics are subtle and hard to test exhaustively; the single canonical implementation means bugs could affect all users. However, strong type safety from Rust mitigates many traditional distributed systems pitfalls.

Active areas of work

The project is maintaining Rust language currency (bumped to edition 2021, rust-version 1.86 in workspace Cargo.toml), integrating columnar 0.12 (workspace.dependencies), enforcing clippy lints across the board, and managing release automation via release-plz.yml. Active monitoring of dependencies through dependabot.yml suggests ongoing maintenance without major API revisions visible in the truncated file list.

🚀Get running

git clone https://github.com/TimelyDataflow/timely-dataflow.git
cd timely-dataflow
cargo build
cargo run --example simple

The output will print seen: 0 through seen: 9, demonstrating the basic dataflow topology.

Daily commands: From repository root: cargo run --example simple or cargo run --example hello (which uses execute_from_args to accept cluster topology args). For tests: cargo test --workspace. For distributed clusters, compile and run with --release for performance; communication layer auto-detects topology via args passed to execute_from_args().

🗺️Map of the codebase

  • timely/Cargo.toml — Root timely crate manifest defining core dataflow abstractions, dependencies, and feature flags that all contributors must understand
  • communication/src/lib.rs — Communication layer entry point that abstracts multi-threaded and distributed networking; essential for understanding inter-worker message passing
  • timely/examples/hello.rs — Canonical minimal example demonstrating the timely dataflow execution model and worker API patterns
  • communication/src/allocator/mod.rs — Allocator trait definitions and implementations governing memory management and data exchange across workers
  • mdbook/src/SUMMARY.md — Index to long-form documentation chapters explaining timely's design philosophy and programming model by example
  • logging/src/lib.rs — Logging infrastructure enabling observability into dataflow execution and event tracing
  • container/src/lib.rs — Generic container abstraction for batching data through the dataflow, fundamental to performance optimization

🛠️How to make changes

Add a new dataflow operator

  1. Define operator trait or struct in timely source or as extension crate (timely/Cargo.toml)
  2. Implement the operator logic operating on streams with scope.stream_from() (timely/examples/hello.rs)
  3. Add example demonstrating operator usage pattern (timely/examples/distinct.rs)
  4. Document in mdbook chapter under appropriate section (mdbook/src/chapter_2/chapter_2.md)

Add a new communication allocator

  1. Implement Allocate and related traits from allocator/mod.rs (communication/src/allocator/mod.rs)
  2. Add allocator module under communication/src/allocator/ (communication/src/allocator/generic.rs)
  3. Register allocator in initialize.rs worker setup function (communication/src/initialize.rs)
  4. Add example demonstrating allocator with comm_hello.rs pattern (communication/examples/comm_hello.rs)

Optimize data throughput with container changes

  1. Modify container abstraction for new batching behavior (container/src/lib.rs)
  2. Update serialization in bytes/src/lib.rs if needed (bytes/src/lib.rs)
  3. Benchmark against existing examples like exchange.rs (timely/examples/exchange.rs)
  4. Add logging instrumentation via logging/src/lib.rs traits (logging/src/lib.rs)

Add a new multi-worker example

  1. Create new example file in timely/examples/ (timely/examples/hello.rs)
  2. Use communication::initialize() for multi-process setup (communication/src/initialize.rs)
  3. Document example logic in corresponding mdbook chapter (mdbook/src/chapter_3/chapter_3.md)
  4. Ensure example runs in CI test matrix (.github/workflows/test.yml)

🔧Why these technologies

  • Rust + cargo workspace — Type safety and zero-cost abstractions critical for low-latency dataflow; workspace structure isolates communication, logging, and runtime concerns
  • Zero-copy allocators (bytes, custom TCP buffer pools) — Minimizes GC pressure and memory copies in high-throughput data movement; latency-sensitive applications cannot afford reallocation overhead
  • Trait-based allocator design (Allocate trait) — Enables pluggable memory strategies (generic, process, zero-copy) without recompiling core engine; supports diverse deployment topologies
  • TCP + optional QUIC for networking — Reliable ordering and connection management for distributed coordination; TCP avoids message loss complexity in timely semantics
  • Event logging as first-class citizen — Observability into distributed execution enables debugging and profiling; logging trait allows custom instrumentation without core modifications

⚖️Trade-offs already made

  • Cyclic dataflow model with logical timestamps vs. DAG-only dataflow

    • Why: Cycles enable iterative and long-running computations (e.g., graph algorithms, incremental updates); DAG systems cannot express these naturally
    • Consequence: Requires frontierTracking and timestamp advancement logic; increases mental model complexity but unlocks expressive power
  • Zero-copy allocators opt-in via feature/compilation, not mandatory

    • Why: Generic allocator works for prototyping and testing; zero-copy adds complexity and platform dependencies (memory registration)
    • Consequence: New users can start simple; production deployments can optimize separately; requires benchmark-driven migration
  • Container abstraction generic over data layout (columnar, row-major, custom)

    • Why: Different domains benefit from different layouts (analytics uses columnar, streaming uses row); one-size-fits-all serialization loses performance
    • Consequence: Operators must be generic over container; more boilerplate in operator definitions; enables domain-specific optimizations
  • Multi-threaded and multi-process workers in single system vs. only distributed

    • Why: Development and small-scale jobs benefit from shared-memory threads; distributed mode needed for production scale
    • Consequence: Allocators must support both; testing can run on single machine; no artificial separation of concerns in code

🚫Non-goals (don't propose these)

  • Not a streaming database or SQL engine—timely is a computational model; SQL translation and optimization are responsibility of layers above
  • Not a long-running cluster scheduler like Kubernetes or Spark—assumes operator code is fast and workers are pre-provisioned
  • Does not provide fault tolerance or checkpointing—dataflow is expected to be rerun on failure; state management is application responsibility
  • Not a real-time guarantees system—cyclic dataflow introduces feedback delay; timing depends on computational load and network conditions
  • Does not handle persistent state or durable queues—data in flight is transient; durability requires external systems

🪤Traps & gotchas

Unsafe code in zero_copy paths: communication/src/allocator/zero_copy/ contains unsafe Rust for memory-mapped buffers and spilling to disk (bytes_slab.rs, spill.rs)—changes here require careful auditing. Distributed time semantics: Timely's notion of time (frontier advancement, capability/obligation tracking) is non-obvious; see examples for correct usage or risk deadlock. Allocator selection at compile time: execute_from_args routes to thread vs. process vs. TCP allocator based on args, but mix-ups in topology specification can cause silent misbehavior rather than errors. Miri testing: The project runs Miri (miri.yml CI) which catches undefined behavior; local changes to unsafe code must pass cargo +nightly miri test to avoid regression. Workspace resolver = 2: Required for proper multi-crate builds; accidental downgrade to resolver = 1 breaks the layout.

🏗️Architecture

💡Concepts to learn

  • Timely Dataflow / Naiad Model — The foundational execution model of this entire codebase; understanding frontiers, capabilities, obligations, and logical timestamps is prerequisite to reading almost any core file.
  • Cyclic Dataflow Graphs — Unlike acyclic DAG systems (Spark, MapReduce), Timely supports feedback loops and iterative algorithms; this is why it's fundamentally different and harder to reason about.
  • Push-Pull Abstraction — The core abstraction for data movement in communication/src/allocator/zero_copy/push_pull.rs; understanding push vs. pull semantics is essential to the communication layer.
  • Zero-Copy Serialization & Memory-Mapped Buffers — Timely avoids serialization overhead via bytes/src/lib.rs and zero_copy allocators (bytes_slab.rs, spill.rs); this is how it achieves low-latency claims.
  • Allocator Trait Pattern — communication/src/allocator/mod.rs defines AllocateBuilder, allowing swappable thread/process/TCP transports; understanding pluggable allocators reveals how Timely scales from laptop to cluster.
  • Work-Stealing & Frontier Advancement — Timely's scheduler must respect logical time; workers steal work, but the frontier (minimum outstanding capability) gates progress; this prevents data races in cyclic graphs.
  • Columnar Data Layout — The container/ crate and columnar 0.12 dependency encode data column-wise for cache efficiency; this is a modern performance optimization distinct from row-oriented systems.
  • MaterializeInc/materialize — Production streaming database built on Timely Dataflow; shows how to apply timely-dataflow to real-world SQL queries and incremental computation.
  • frankmcsherry/differential-dataflow — Extends Timely Dataflow with incremental graph algorithms and join semantics; natural companion for users needing iterative graph processing.
  • apache/arrow-rs — Columnar data format used by Timely (columnar crate 0.12); used for interchange and efficient serialization across process boundaries.
  • tokio-rs/tokio — Async runtime; Timely intentionally avoids async to guarantee latency predictability, but users often pair Timely with Tokio for I/O without blocking workers.
  • serde-rs/serde — De-facto Rust serialization framework; Timely's communication layer uses serde implicitly for data interchange in allocators.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add integration tests for zero-copy allocator TCP communication

The communication/src/allocator/zero_copy/ module has multiple complex components (tcp.rs, allocator_process.rs, spill.rs, stream.rs) but there are no visible integration tests verifying end-to-end TCP communication with zero-copy semantics. The existing examples (comm_hello.rs, spill_stress.rs) are good but formal integration tests would catch regressions in the critical networking path.

  • [ ] Create communication/tests/zero_copy_tcp_integration.rs
  • [ ] Add tests for basic point-to-point TCP communication using ZeroCopyAllocator
  • [ ] Add tests for multi-worker scenarios with tcp.rs
  • [ ] Add tests for spill behavior under pressure (reference communication/examples/spill_stress.rs)
  • [ ] Ensure tests are included in test.yml CI workflow

Add MIRI compatibility tests for unsafe code in bytes and allocator modules

The miri.yml workflow exists but appears minimal. The bytes/src/lib.rs and communication/src/allocator/zero_copy/ modules likely contain unsafe code for performance (zero-copy, custom allocators). Add targeted MIRI tests to detect undefined behavior and improve memory safety validation without full MIRI runs on all code.

  • [ ] Review unsafe code blocks in bytes/src/lib.rs and communication/src/allocator/zero_copy/allocator.rs
  • [ ] Create communication/tests/miri_unsafe.rs with isolated MIRI-compatible tests
  • [ ] Add miri-specific test invocation to .github/workflows/miri.yml
  • [ ] Document MIRI limitations for async/network code in CONTRIBUTING.md
  • [ ] Ensure tests compile and run under cargo +nightly miri test

Complete documentation for timely/examples/ with mdbook integration guide

The README mentions long-form documentation in mdbook format (mdbook/src/chapter_*/) but the file structure shows incomplete chapters. There's a gap between the brief README and detailed mdbook content. Add a specific guide section documenting how to run examples from communication/examples/ and link them from mdbook.

  • [ ] Create mdbook/src/chapter_3/chapter_3.md covering 'Communication Examples'
  • [ ] Document communication/examples/comm_hello.rs, lgalloc.rs, and spill_stress.rs with setup/execution instructions
  • [ ] Add cross-references from existing chapters to relevant examples
  • [ ] Update mdbook/src/SUMMARY.md to include the new chapter
  • [ ] Add a section in CONTRIBUTING.md referencing where to find and understand examples

🌿Good first issues

  • Add comprehensive doc tests to communication/src/allocator/mod.rs. The AllocateBuilder trait and its implementations (thread.rs, process.rs) lack examples showing how to instantiate allocators; new contributors struggle to understand the trait API.: Medium: Improves onboarding, catches regressions early via doc tests.
  • Expand communication/examples/ with a cluster-topology example. Currently comm_hello.rs exists but lacks detailed comments on how to set TIMELY_WORKER_THREADS, TIMELY_PROCESS_ID, and port assignment; add a documented multi-process launcher script.: Medium: Distributed setup is the hardest part; better examples reduce friction for users scaling beyond single-thread.
  • Add micro-benchmarks for bytes/ and container/ in their respective Cargo.tomls under [[bench]]. These low-level crates lack performance regression testing despite being hot paths in communication.: Low-to-Medium: Catches performance regressions early; these crates are foundational so regressions ripple through the entire system.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • d93ed19 — Benchmark spill machinery (#791) (frankmcsherry)
  • b4e5ef9 — V0 spilling MergeQueue (#789) (frankmcsherry)
  • 866d5c3 — chore: release v0.29.0 (#776) (github-actions[bot])
  • 60de304 — Move logging to subgraph building (#788) (frankmcsherry)
  • 27c921d — Implement Copy for Scope (#787) (frankmcsherry)
  • 253d2ba — Box operator logic by default (#786) (frankmcsherry)
  • 52ecffb — Return lifetimes to Scope and friends (#785) (frankmcsherry)
  • 2a4cb25 — Make some useful types pub (#782) (frankmcsherry)
  • 2cff8fe — Subscope builder (#781) (frankmcsherry)
  • cb94c22 — Convert Scope trait to type (#780) (frankmcsherry)

🔒Security observations

The codebase demonstrates generally good security practices with modern Rust tooling and comprehensive lint configurations. However, several areas warrant attention: (1) distributed system components require security review for network communication, authentication, and authorization; (2) zero-copy allocators containing unsafe code need thorough auditing; (3) dependency management could be more explicit; (4) broad lint allowances should be periodically reviewed. No hardcoded secrets, injection vulnerabilities, or critical misconfigurations were detected in the visible structure. The project uses Rust's type system and modern dependency management effectively, but network communication security and unsafe code blocks should be priority security review areas for a distributed system.

  • Medium · Missing Dependency Version Pinning — Cargo.toml - workspace.dependencies section. The workspace dependencies in Cargo.toml use loose version specifications (e.g., columnar = "0.12"). This allows transitive dependency updates that could introduce vulnerabilities. While Cargo.lock should mitigate this in applications, libraries should consider more explicit versioning strategies. Fix: Consider using more specific version constraints (e.g., "=0.12.x" or "0.12.y") and regularly audit transitive dependencies using 'cargo audit'.
  • Low · Broad Clippy Lint Allowances — Cargo.toml - workspace.lints.clippy section. Several Clippy lints are explicitly allowed in clippy.toml (type_complexity, option_map_unit_fn, wrong_self_convention, should_implement_trait, module_inception). While some are reasonable, overly permissive lint configurations could allow problematic code patterns to slip through. Fix: Regularly review allowed lints and consider enforcing stricter checks. Document why each exception is necessary.
  • Low · Distributed System Security Considerations — communication/src/allocator/zero_copy/tcp.rs, communication/src/networking.rs. The codebase implements distributed dataflow with networking components (communication/src/allocator/zero_copy/tcp.rs, networking.rs). Distributed systems require careful security consideration for network communication, authentication, and authorization between nodes. Fix: Conduct a security review of network communication protocols, implement proper authentication/authorization between distributed nodes, validate all network inputs, and consider TLS encryption for inter-node communication.
  • Low · Memory Safety in Zero-Copy Allocators — communication/src/allocator/zero_copy/ directory. The zero-copy allocator implementation (communication/src/allocator/zero_copy/) handles memory directly. Any unsafe code blocks require careful review to prevent buffer overflows, use-after-free, or data races. Fix: Thoroughly audit all unsafe code blocks, especially in allocator.rs, bytes_slab.rs, and stream.rs. Use tools like Miri for detecting undefined behavior and consider memory sanitizers in CI/CD.
  • Low · Incomplete Clippy Configuration — Cargo.toml - workspace.lints.clippy section (last line). The clippy configuration in Cargo.toml appears incomplete - the last line 'suspicious_unary' is cut off and doesn't have a severity level specified. Fix: Complete the configuration by adding the proper severity level for 'suspicious_unary' and ensure all clippy rules are properly terminated.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · TimelyDataflow/timely-dataflow — RepoPilot