Jesse A. Green / notebook

Twitter's "The Algorithm" — Administrator & Developer Guide

Generated May 2026 from twitter/the-algorithm at c54bec0

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide covers the architecture, internals, configuration, deployment patterns, and code structure of Twitter's open-sourced recommendation algorithm. It is written for platform engineers, ML engineers, and architects who need to understand how these systems were designed and operated, either for study, adaptation, or reimplementation.

1. Architecture Overview

What the System Does

Twitter's recommendation algorithm is a distributed system of ~20 interconnected microservices that collectively decide what content users see across Home Timeline, Search, Notifications, and Who to Follow. The system processes billions of tweets and hundreds of millions of user interactions to produce personalized feeds in real time.

The architecture follows a multi-stage candidate generation → ranking → filtering pattern, where each stage progressively narrows and scores content. Services communicate primarily via Thrift RPC (using Twitter's Finatra/Finagle stack), with Kafka for event streaming and HDFS/Manhattan for persistent storage.

System Architecture

┌──────────────────────────────────────────────────────────────────┐
│                        PRODUCT LAYER                             │
│  ┌─────────────┐  ┌─────────────┐  ┌────────────┐  ┌─────────┐ │
│  │ Home Mixer   │  │ Tweet Mixer │  │ Push Svc   │  │ Search  │ │
│  │ (For You/    │  │ (content    │  │ (notif     │  │ Root    │ │
│  │  Following)  │  │  blending)  │  │  ranking)  │  │         │ │
│  └──────┬───────┘  └──────┬──────┘  └─────┬──────┘  └────┬────┘ │
│         │                 │               │               │      │
│  ┌──────┴─────────────────┴───────────────┴───────────────┘      │
│  │           Product Mixer Framework                             │
│  │     (pipeline orchestration, feature hydration, scoring)      │
│  └──────┬────────────────────────────────────────────────────┘   │
└─────────┼────────────────────────────────────────────────────────┘
          │
┌─────────┼────────────────────────────────────────────────────────┐
│         ▼          RECOMMENDATION LAYER                          │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ Timeline     │  │ CR-Mixer     │  │ Follow Recs  │           │
│  │ Ranker       │  │ (content     │  │ Service      │           │
│  │ (scoring)    │  │  candidates) │  │ (who to      │           │
│  │              │  │              │  │  follow)     │           │
│  └──────────────┘  └──────────────┘  └──────────────┘           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ SimClusters  │  │ Topic Social │  │ Recos        │           │
│  │ ANN          │  │ Proof        │  │ Injector     │           │
│  └──────────────┘  └──────────────┘  └──────────────┘           │
└──────────────────────────────────────────────────────────────────┘
          │
┌─────────┼────────────────────────────────────────────────────────┐
│         ▼           FEATURE & SIGNAL LAYER                       │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ Graph Feature│  │ User Signal  │  │ Representation│          │
│  │ Service      │  │ Service      │  │ Manager/Scorer│          │
│  └──────────────┘  └──────────────┘  └──────────────┘           │
│  ┌──────────────┐  ┌──────────────┐                              │
│  │ Unified User │  │ VisibilityLib│                              │
│  │ Actions      │  │ (moderation) │                              │
│  └──────────────┘  └──────────────┘                              │
└──────────────────────────────────────────────────────────────────┘
          │
┌─────────┼────────────────────────────────────────────────────────┐
│         ▼           DATA & ML LAYER                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ Earlybird    │  │ TweetyPie    │  │ ANN Service  │           │
│  │ (search      │  │ (tweet       │  │ (nearest     │           │
│  │  index)      │  │  storage)    │  │  neighbor)   │           │
│  └──────────────┘  └──────────────┘  └──────────────┘           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐           │
│  │ Navi (model  │  │ twml (ML     │  │ Trust &      │           │
│  │  serving)    │  │  training)   │  │ Safety Models│           │
│  └──────────────┘  └──────────────┘  └──────────────┘           │
└──────────────────────────────────────────────────────────────────┘
          │
┌─────────┼────────────────────────────────────────────────────────┐
│         ▼           INFRASTRUCTURE                               │
│  Aurora (scheduling) │ Kafka (streaming) │ HDFS (storage)        │
│  Manhattan (KV)      │ Strato (data)     │ ZooKeeper (coord)     │
│  Thrift (RPC)        │ Finagle (network) │ Finatra (framework)   │
└──────────────────────────────────────────────────────────────────┘

Note

All Scala/Java services in this repository use Twitter's Finatra framework for HTTP/Thrift server lifecycle, dependency injection (via Google Guice), and request filtering. The Finagle library provides the underlying RPC, load balancing, and connection pooling.

Component Inventory

Component Path Language Role
Home Mixer home-mixer/ Scala Home timeline assembly (For You, Following)
Timeline Ranker timelineranker/ Scala Tweet scoring and ranking
CR-Mixer cr-mixer/ Scala Content-based recommendation candidates
Follow Recs Service follow-recommendations-service/ Scala Who to Follow candidate gen + ranking
Product Mixer product-mixer/ Scala Generic pipeline framework
TweetyPie tweetypie/ Scala Tweet storage, hydration, CRUD
Push Service pushservice/ Scala + Python Notification ranking (heavy/light)
Earlybird src/java/com/twitter/search/ Java Real-time tweet search (Lucene-based)
VisibilityLib visibilitylib/ Scala Content moderation rules engine
Graph Feature Service graph-feature-service/ Scala User-user graph feature computation
User Signal Service user-signal-service/ Scala User behavioral signal aggregation
Unified User Actions unified_user_actions/ Scala Cross-product event tracking
SimClusters src/scala/com/twitter/simclusters_v2/ Scala Topic embedding generation (batch)
SimClusters ANN simclusters-ann/ Scala Topic-based nearest neighbor
ANN Service ann/ Scala + Java Approximate nearest neighbor (HNSW/Annoy/FAISS)
Representation Manager representation-manager/ Scala Embedding storage and versioning
Representation Scorer representation-scorer/ Scala Embedding similarity computation
Navi navi/ Rust ML model serving (TF/PyTorch/ONNX)
twml twml/ Python + C++ ML training framework (on TF)
Trust & Safety Models trust_and_safety_models/ Python NSFW, toxicity, abusive content models
Recos Injector recos-injector/ Scala Recommendation event injection
Topic Social Proof topic-social-proof/ Scala Topic relevance scoring
Tweet Mixer tweet-mixer/ Scala Tweet blending for mixed feeds
Interaction Graph src/scala/com/twitter/interaction_graph/ Scala User interaction graph processing
Timelines timelines/ Python + Scala Timeline data processing and model training

Technology Stack

Layer Technology
Primary Languages Scala 2.12, Java 11, Python 3.7, Rust
Build System Bazel (Scala/Java), Cargo (Rust), pip/setuptools (Python)
RPC Framework Apache Thrift via Finagle
Service Framework Finatra (HTTP + Thrift), mTLS
ML Training TensorFlow (via twml), Keras
ML Serving Navi (TF, PyTorch, ONNX via gRPC)
Search Engine Apache Lucene (custom Earlybird)
Stream Processing Apache Kafka
Batch Processing Apache Beam, Scalding, Scio (on Hadoop/HDFS)
Coordination Apache ZooKeeper
Storage Manhattan (KV), HDFS, Feature Store
Deployment Aurora (Mesos scheduler)
Graph Processing GraphJet (real-time), Scalding (batch)
Embeddings SimClusters, Word2Vec (Follow2Vec), WHIMP (cosine similarity)
ANN Algorithms HNSW, Annoy, FAISS, brute-force
Monitoring Prometheus (Navi), Stats (Finagle), Decider (feature flags)

Data Flow: Home Timeline Request

1. User opens For You tab
2. Home Mixer receives request
3. Product Mixer orchestrates pipeline:
   a. Earlybird → in-network tweet candidates (recent tweets from followed accounts)
   b. CR-Mixer → out-of-network candidates (content recs from multiple signals)
   c. SimClusters ANN → topic-relevant candidates
4. Feature hydration:
   a. Graph Feature Service → user-user graph features
   b. User Signal Service → engagement history, behavioral signals
   c. Representation Manager → user/tweet embeddings
5. Timeline Ranker scores all candidates with heavy ranking model
6. VisibilityLib filters by safety rules, content policy
7. Home Mixer assembles final timeline with mixing rules
8. Response returned to client

2. System Requirements

Runtime Infrastructure Dependencies

Dependency Purpose Required For
Apache Aurora Job scheduling and deployment All Scala/Java services
Apache Kafka Event streaming UUA, Earlybird indexing, feature updates
HDFS Distributed file storage Batch jobs, model storage, embeddings
Manhattan Key-value store Feature serving, embedding lookup
Strato Data access layer Feature Store, various data sources
Apache ZooKeeper Service coordination Dataset pointers, config distribution
Finagle/Finatra RPC and service framework All Scala/Java services
Feature Store ML feature serving Model feature hydration

Hardware Requirements (Per Service)

Based on Aurora job configurations in the ground truth:

Service CPU RAM Disk Notes
ANN Index Builder 32 cores 150 GB 60 GB GPU optional, CUDA 11.2 for ML
Navi Model Serving 8+ cores 16+ GB Varies GPU recommended for TF/PyTorch
twml Training 2+ cores 8+ GB Varies GPU required for deep models
Earlybird High High SSD Lucene index in memory/SSD
Graph Feature Service Moderate High Moderate Graph data in memory

Important

The ANN Dataflow worker Dockerfile specifies CUDA 11.2.2 with cuDNN 8 on Ubuntu 20.04 as the reference GPU environment. Python 3.7 is pinned explicitly.

3. Configuration Reference

Navi reads a JSON configuration file specifying model locations and runtime parameters:

{
  "model_dir": ["/path/to/model1", "/path/to/model2"],
  "inter_op_parallelism": 1,
  "intra_op_parallelism": 4
}

Key configuration functions (from navi/navi/src/lib.rs):

Function Purpose
read_config(meta_file) Parse JSON config from file
get_config_or_else(config, key, default_fn) Read config key with computed default
get_config_or(config, key, default) Read config key with string default
get_meta_dir() Get model metadata directory path

Navi CLI arguments (from navi/navi/src/cli_args.rs):

Argument Type Description
--model-dir Vec<String> Model directory paths
--config String Path to JSON configuration file

twml Training Configuration (Complete CLI Reference)

All 70 CLI parameters extracted from twml/twml/argument_parser.py:

Core Training Parameters

Flag Type Default Description
--save_dir str (required) Training result directory (local or hdfs://)
--export_dir str None SavedModel export directory for prediction serving
--train.batch_size int 32 Samples per training batch
--eval.batch_size int 32 Samples per evaluation batch
--train.learning_rate float 0.002 Learning rate (scales gradient update)
--train.steps int -1 Training batches before evaluation (-1 = full dataset)
--eval.steps int -1 Steps per evaluation (-1 = full dataset)
--train.max_steps int None Global step limit (None = one train/eval cycle)
--optimizer str SGD Optimizer: SGD, Adagrad, Adam, Ftrl, Momentum, RMSProp, LazyAdam, DGC
--data_threads int 2 Dataset loading threads
--num_workers int None Hogwild workers for single-node training

Evaluation & Early Stopping

Flag Type Default Description
--eval.period int 600 Seconds between evaluations in train_and_evaluate
--eval.delay int 120 Seconds before first evaluation
--train.early_stop_patience int -1 Max evaluations without improvement (-1 = disabled)
--train.early_stop_tolerance float 0 Minimum improvement threshold
--train.log_metrics flag False Log metrics during training (10-20% perf hit)

Warning

Early stopping (--train.early_stop_patience) cannot be used with --distributed mode. Attempting to combine them will produce undefined behavior.

Distributed Training

Flag Type Default Description
--distributed flag False Enable distributed train_and_evaluate
--distributed_training_cleanup flag False Stop TwitterSetDeployment on restart (GKE)
--disable_auto_ps_shutdown flag False Disable auto parameter server shutdown
--train.dataset_shards int None Number of data partitions for codistillation
--train.dataset_shard_index int None Which data partition to use (0-indexed)

Checkpointing & Monitoring

Flag Type Default Description
--config.save_checkpoints_secs int 600 Checkpoint save interval (seconds)
--config.keep_checkpoint_max int 20 Maximum checkpoints to retain
--config.tf_random_seed int None TensorFlow random seed
--overwrite_save_dir flag False Delete existing save_dir contents
--disable_tensorboard flag False Don't start TensorBoard server
--tensorboard_port int None TensorBoard port (ignored if disabled)
--health_port int None Health endpoint port (set by twml_cli)
--stats_port int None Stats endpoint port
--experiment_tracking_path str None ML Dashboard tracking path (user:project:experiment:run)
--disable_experiment_tracking flag False Disable experiment tracking

Gradient & Optimization

Flag Type Default Description
--gradient_noise_scale float None 0-mean normal noise scale
--clip_gradients float None Global gradient norm clipping
--dgc.density float 0.1 Deep gradient compression density (top 10%)
--dgc.density_decay bool True Enable exponential density decay
--dgc.density_decay_steps int 10000 Decay step interval
--dgc.density_decay_rate float 0.5 Decay rate
--dgc.min_density float 0.1 Minimum density after decay
--dgc.accumulation bool False Accumulate small gradients
--show_optimizer_summaries flag False Display gradients/LR in TensorBoard
--num_mkl_threads int 1 MKL parallelism threads

Learning Rate Decay

Flag Type Default Description
--decay_steps float None Steps for exponential/polynomial/inverse/cosine decay
--exponential_decay_rate float None Rate for exponential decay
--end_learning_rate float 0.0001 End rate for polynomial decay

Supported decay schedules: exponential, polynomial, piecewise_constant, inverse, cosine_decay, cosine_restarts_decay.

Feature Importance

Flag Type Default Description
--feature_importance.algorithm str (none) serial or tree
--feature_importance.sensitivity float 0.03 Max metric drop before tree expansion stops
--feature_importance.example_count int 10000 Examples for importance computation
--feature_importance.data_dir str None Dataset path (defaults to eval dir)
--feature_importance.metric str roc_auc Metric for tree algorithm stop criterion
--feature_importance.is_metric_larger_the_better flag False Metric direction (larger = better)
--feature_importance.is_metric_smaller_the_better flag False Metric direction (smaller = better)
--feature_importance.dont_build_tree flag False Skip trie building for tree algorithm
--feature_importance.split_feature_group_on_period flag False Split groups on period vs. optimal prefix

ANN Index Builder Configuration

The ANN index builder accepts these Aurora profile parameters:

Parameter Type Description
profile.name string Aurora job name
profile.role string Aurora role
profile.hadoop_cluster string Hadoop cluster (e.g., dw2-smf1)
profile.entity_kind enum Entity type: user, tweet, word, url, tfwId
profile.num_dimensions int Embedding dimensionality
profile.metric enum Distance metric: InnerProduct, Cosine, L2
profile.concurrency_level int Parallel index inserts (set to CPU count)
profile.algo enum Algorithm: hnsw, annoy, brute_force
profile.output_dir string HDFS output path for serialized index

HNSW-specific:

Parameter Default Description
profile.ef_construction — Build-time recall parameter (higher = better recall, slower build)
profile.max_m — Max connections per node (6-48 optimal, 16 recommended)
profile.expected_elements — Approximate index size

Annoy-specific:

Parameter Default Description
profile.annoy_num_trees — Number of trees (more = better accuracy, larger index)

FAISS-specific (load testing only):

Parameter Default Description
profile.faiss_nprobe 1 Number of clusters to probe
profile.faiss_quantizerEf 0 Quantizer ef parameter
profile.faiss_quantizerKfactorRF 0 Quantizer k-factor
profile.faiss_quantizerNprobe 0 Quantizer nprobe
profile.faiss_ht 0 Hamming threshold

Note

FAISS parameters accept comma-separated lists for grid search during load testing (e.g., --bind=profile.faiss_nprobe=1,3,9,27,81,128).

Environment Variables

Variable Source Description
TWML_JOB_CLUSTER twml/twml/util.py:917 Cluster for distributed training
TWML_JOB_ROLE twml/twml/util.py:918 Job role identifier
TWML_JOB_ENV twml/twml/util.py:919 Environment (staging/production)
TWML_DISTRIBUTED_BASE_JOBNAME twml/twml/util.py:920 Base name for distributed jobs
HADOOP_CONF_DIR — HDFS configuration (required for hdfs:// paths)

4. Deployment & Scaling

Deployment Model

All production services deploy on Apache Aurora (a Mesos scheduler). Aurora job configurations are defined in .aurora files using Thermos templates.

Deployment pattern:

  1. Build service bundle with Bazel: ./bazel bundle <target>:deploy --bundle-jvm-archive=zip
  2. Upload bundle to Packer (Twitter's artifact storage)
  3. Create Aurora job: aurora job create <cluster>/<role>/<env>/<name> <config>.aurora

Service Architecture Patterns

All Scala services follow a consistent pattern using Finatra:

object Main extends ServerMain

class ServerMain extends ThriftServer with Mtls {
  override val name = "service-name"
  override val modules: Seq[Module] = Seq(/* Guice modules */)

  override def configureThrift(router: ThriftRouter): Unit = {
    router
      .filter[LoggingMDCFilter]
      .filter[TraceIdMDCFilter]
      .filter[ThriftMDCFilter]
      .filter[StatsFilter]
      .add[ServiceController]
  }

  override protected def warmup(): Unit = {
    handle[WarmupHandler]()
  }
}

Standard filter chain: LoggingMDCFilter → TraceIdMDCFilter → ThriftMDCFilter → AccessLoggingFilter → StatsFilter → controller.

Earlybird Cluster Topology

Earlybird splits the tweet index across three cluster types:

Cluster Content Freshness Shard Strategy
Realtime Public tweets Last ~7 days Time-based partitioning
Protected Protected tweets Last ~7 days Time-based partitioning
Archive All tweets All time (up to ~2 days ago) Time-based partitioning

Each cluster uses multiple partitions with replication. Earlybird roots fan out queries across partitions and merge responses.

Indexing pipeline:

  • Ingesters consume from Kafka, extract fields/features, write to intermediate Kafka topics
  • Earlybird instances consume from intermediate topics and update in-memory Lucene indexes
  • Feature Update Service pushes real-time engagement counts (likes, retweets, replies)

Navi compiles to three separate binaries depending on ML backend:

Binary Feature Flag Backend
navi tf TensorFlow SavedModel
navi_torch torch PyTorch TorchScript
navi_onnx onnx ONNX Runtime

Each binary serves predictions via the TensorFlow Serving gRPC protocol (prediction_service.proto), with support for the KFServing v2 inference protocol.

Tip

Navi supports hot model reloading. When a new model version directory appears under the configured model_dir, Navi automatically detects the version timestamp and loads the new model without restart.

5. Operations

Monitoring

Navi exposes Prometheus metrics via an HTTP endpoint (Warp-based). Key metrics:

Metric Type Description
Prediction latency Histogram Per-model inference time distribution
Batch size Histogram Dynamic batching size distribution
Model load time Gauge Time to load model version
Request count Counter Total prediction requests

Scala services use Finagle's built-in StatsReceiver for metrics, exposed via the standard Finagle admin interface.

Note

All Scala services include StatsFilter in their Thrift filter chain, which automatically tracks request rate, latency percentiles, and error rates per endpoint.

Feature Flags (Deciders)

Services use Twitter's Decider system for feature flags and gradual rollouts. Decider modules are injected via Guice:

override val modules: Seq[Module] = Seq(
  DeciderModule,
  // ...
)

Deciders control traffic routing, experiment allocation, and feature availability without redeployment.

Health Checks

Finatra services expose health endpoints via the admin HTTP interface. twml training jobs expose health on a configurable --health_port for graceful shutdown coordination.

Tip

For twml distributed training, the --disable_auto_ps_shutdown flag prevents the parameter server from shutting down prematurely when individual workers fail. Use this for fault-tolerant long-running jobs.

Batch Processing Operations

SimClusters, interaction graphs, and embedding generation run as batch Scalding/Scio jobs on Hadoop:

# Example: Run embedding sampling job
oscar hdfs \
  --screen --tee log.txt \
  --hadoop-client-memory 6000 \
  --bundle embeddingformat-deploy \
  --host hadoopnest1.smf1.twitter.com \
  --tool com.twitter.scalding.entityembeddings.util.EmbeddingFormat.EmbeddingSamplingJob -- \
  --entity_kind user \
  --input.embedding_path $INPUT_PATH \
  --input.embedding_format usertensor \
  --output.embedding_path $OUTPUT_PATH \
  --output.embedding_format tab \
  --sample_percent 0.1

Supported embedding formats: usertensor, usercontinuous, comma, tab.

6. Performance

Earlybird Optimizations

  • Incremental indexing: New tweets are indexed in real-time as they arrive from Kafka, maintaining index freshness
  • Single-writer, multiple-reader: Eliminates write contention while supporting high query concurrency
  • Partitioned index: Horizontal scaling across shards, with roots handling fan-out and merge
  • Column-stride field indexes: Optimized for per-document feature lookups (engagement counts, timestamps)

Navi implements dynamic batching to maximize GPU/CPU utilization:

  • Incoming requests are buffered in a BatchPredictor
  • Batches are flushed when either the size limit or timeout is reached (duration_past check)
  • Responses are demultiplexed back to individual request channels

Product Mixer Quality Factors

Product Mixer pipelines support quality factors — runtime parameters that trade off result quality for latency:

// From pipeline framework
class QualityFactorStatus {
  // Dynamically adjust pipeline behavior based on latency targets
}

When latency increases, quality factors can reduce candidate counts, simplify feature hydration, or skip expensive scoring stages.

7. Security

Authentication & Authorization

  • All Scala services use mTLS (mutual TLS) via Finatra's Mtls trait
  • Navi supports mTLS with x509 certificate verification (x509-parser crate)
  • Inter-service communication is authenticated via Thrift client IDs (ThriftClientIdModule)

Warning

The open-source release does not include the internal certificate infrastructure. Services expect valid mTLS certificates for production operation. For local development, you would need to set up a local CA or disable mTLS.

Content Safety

VisibilityLib is the centralized content moderation engine. It evaluates rules against:

  • Content labels — safety classifications applied to tweets and users
  • Visibility actions — outcomes like hide, filter, tombstone, interstitial
  • Rule conditions — composable predicates combining labels, user state, and context

The visibilitylib/src/main/scala/com/twitter/visibility/models/ directory (24 files, 126K chars) defines the complete vocabulary of content labels and actions.

Trust & Safety ML Models

Model Path Purpose
NSFW Text Classifier trust_and_safety_models/nsfw/ Text-based NSFW detection
Toxicity Classifier trust_and_safety_models/toxicity/ Toxic content detection
Abusive Content Model trust_and_safety_models/abusive/ Abusive behavior classification

The toxicity trainer supports multiple loss functions: BCE, masked BCE, CCE, sCCE, Focal_BCE, inv_KL_loss, with configurable optimizers and multi-fold training.

Caution

The trust and safety models are trained on sensitive data. The model architectures and training code are included, but training data is not part of the open-source release.

8. Developer Internals

Repository Structure

the-algorithm/                          # Root (7,651 files, 12.3M source chars)
├── home-mixer/                         # Home timeline product pipeline
│   └── server/src/main/scala/          # Scala service implementation
├── timelineranker/                     # Tweet ranking service
│   ├── server/                         # Server with config and Scala source
│   ├── client/                         # Client library
│   └── common/                         # Shared models
├── follow-recommendations-service/     # Who to Follow
│   ├── server/                         # Server implementation
│   ├── common/                         # 54+ model files, candidate sources
│   └── thrift/                         # Thrift service definitions
├── cr-mixer/                           # Content recommendation mixer
│   ├── server/                         # Server with 9 core modules
│   └── thrift/                         # Thrift definitions
├── product-mixer/                      # Generic pipeline framework
│   ├── core/                           # Pipeline, model, feature, controller
│   ├── component-library/              # Reusable components (scorers, features)
│   └── shared-library/                 # Shared utilities (observers)
├── tweetypie/                          # Tweet storage service
│   ├── server/                         # 49 handler files, 22 config files
│   ├── common/                         # Shared types
│   └── servo/                          # Request/repo/json/decider subsystems
├── pushservice/                        # Push notification service
│   └── src/main/python/models/         # Heavy/light ranking models
├── visibilitylib/                      # Content moderation
│   └── src/main/scala/                 # 24 model files, features, rules, builders
├── src/                                # Core shared source
│   ├── java/com/twitter/search/        # Earlybird search (Java)
│   ├── scala/com/twitter/              # SimClusters, interaction graph, recos
│   ├── python/                         # Deepbird timeline models
│   └── thrift/                         # Shared Thrift definitions
├── twml/                               # Twitter ML library
│   ├── twml/                           # Python package (17 files, 180K chars)
│   ├── twml_common/                    # Common utilities
│   └── libtwml/                        # C++ native library (21 files, 112K chars)
├── navi/                               # ML model serving (Rust)
│   ├── navi/                           # Main server (9 src files, 100K chars)
│   ├── dr_transform/                   # Data record transformer
│   ├── segdense/                       # Feature densification
│   └── thrift_bpr_adapter/             # Thrift BPR parsing (127K chars)
├── ann/                                # Approximate Nearest Neighbor
│   └── src/main/scala/com/twitter/ann/ # Common, query server, scalding
├── graph-feature-service/              # Graph features
│   └── src/main/scala/                 # Server + worker architecture
├── user-signal-service/                # User signals
│   ├── server/                         # 18 signal types
│   └── thrift/                         # Service definitions
├── unified_user_actions/               # Event tracking
│   ├── adapter/                        # Event adapters
│   ├── kafka/                          # Kafka serialization
│   ├── enricher/                       # Event enrichment
│   ├── service/                        # UUA service
│   └── client/                         # Client library
├── representation-manager/             # Embedding management
│   ├── server/                         # Migration, config, common
│   └── client/                         # Client with config
├── representation-scorer/              # Embedding scoring
├── recos-injector/                     # Recommendation injection
├── trust_and_safety_models/            # Safety ML models
│   ├── nsfw/                           # NSFW classifier
│   ├── toxicity/                       # Toxicity classifier
│   └── abusive/                        # Abusive content model
├── topic-social-proof/                 # Topic relevance
├── simclusters-ann/                    # SimCluster nearest neighbor
├── tweet-mixer/                        # Tweet blending (20 feature files)
├── timelines/                          # Timeline data processing
├── science/                            # Science/search tools
└── ci/                                 # CI (minimal: exit 0)

Architecture Deep Dive: Product Mixer Framework

Product Mixer is the foundational framework for all product pipelines. Key abstractions:

Pipeline types:

  • MixerPipeline — top-level pipeline combining multiple candidate sources
  • CandidatePipeline — produces candidates from a single source
  • RecommendationPipeline — end-to-end recommendation pipeline
  • ScoringPipeline — scoring-only pipeline

Pipeline steps (from product-mixer/core/src/main/scala/com/twitter/product_mixer/core/pipeline/):

  • Step trait — base for all pipeline steps
  • FailOpenPolicy — determines behavior on candidate pipeline failure (Always, Never, or custom category set)
  • InvalidStepStateException — thrown when a step's required data is missing
  • NewPipelineArrowBuilder — constructs Stitch arrows for pipeline execution

Component types (from product-mixer/component-library/):

  • Candidate sources
  • Feature hydrators (query-level and candidate-level)
  • Scorers (with common scorer abstractions)
  • Filters
  • Decorators (URT builders for promoted content, articles, etc.)
  • Selectors and sorters
  • Marshallers (URT, RTF, slice response formats)

Observation: The product-mixer/shared-library/src/main/scala/com/twitter/product_mixer/shared_library/observer/ (3 files, 10.5K chars) provides standardized observability wrappers for pipeline components.

Architecture Deep Dive: ANN Service

The ANN service (ann/src/main/scala/com/twitter/ann/common/) provides a generic interface for approximate nearest neighbor operations:

Core abstractions (from Api.scala):

  • EntityEmbedding[T] — entity with associated embedding vector
  • Queryable[T, P, D] — query interface with query() and queryWithDistance()
  • Appendable[T, P, D] — mutable index with append() and toQueryable()
  • RuntimeParams — algorithm-specific runtime parameters (e.g., HNSW ef, Annoy num_trees_to_search)
  • Distance[D] — distance metric abstraction

ID serialization (from AnnInjections.scala):

  • LongInjection, StringInjection, IntInjection — and their Java boxed variants
  • Used for entity ID → byte array conversion in index storage

Query server (from ann/src/main/scala/com/twitter/ann/service/query_server/common/, 9 files, 27K chars):

  • Finatra ThriftServer with standard filter chain
  • Warmup handler for index pre-loading
  • Supports multiple index types per server instance

Architecture Deep Dive: Navi Model Serving

Navi is a Rust-based high-performance model serving system. Key components:

Core types (from navi/navi/src/):

Module Key Types Purpose
batch.rs BatchPredictor Dynamic request batching
bootstrap.rs TensorInput, TensorInputEnum Model bootstrap and input types
cli_args.rs Args Command-line argument parsing (clap)
lib.rs TensorReturnEnum, PredictResult, TensorScores, PredictMessage, Callback Core prediction types
predict_service.rs PredictService Model management and routing
tf_model.rs TFModel, TFTensorEnum TensorFlow backend
torch_model.rs TorchModel PyTorch backend
onnx_model.rs OnnxModel ONNX Runtime backend
metrics.rs register_custom_metrics, metrics_handler Prometheus metrics

Data processing pipeline (from navi/dr_transform/ and navi/segdense/):

Crate Purpose
dr_transform Converts Thrift BatchPredictionRequest to PyTorch tensors
segdense Segment-dense feature transform (schema-driven densification)
bpr_thrift Thrift parser for Batch Prediction Request protocol

Thrift data types (from navi/thrift_bpr_adapter/thrift/src/, 6 files, 127K chars):

  • DataRecord — feature container (binary, continuous, discrete, string, sparse features)
  • CompactDataRecord — space-optimized variant
  • TensorRecord — tensor-based feature container
  • BatchPredictionRequest / BatchPredictionResponse — request/response envelopes
  • Tensor types: StringTensor, Int32Tensor, Int64Tensor, FloatTensor, DoubleTensor, BoolTensor, RawTypedTensor, BinaryTensor
  • Sparse tensor types: COOSparseTensor, SparseTensor (enum)

Architecture Deep Dive: twml

twml is Twitter's ML library, split into Python and C++ layers:

Python layer (twml/twml/, 17 files, 181K chars):

Module Key Classes/Functions Purpose
argument_parser.py SortingHelpFormatter, DefaultSubcommandArgParse CLI argument parsing (70 args)
dataset.py BlockFormatDataset TF Dataset from Twitter's block format
hooks.py StepProgressHook, EarlyStopHook, MetricsUpdateHook, EarlyStopDuration, StopAtStepHook TF SessionRunHooks for training lifecycle
feature_config.py FeatureConfig, FeatureConfigBuilder Feature specification and validation
input_fns.py default_input_fn TF Estimator input function builders
learning_rate_decay.py (6 decay strategies) Learning rate scheduling
metrics.py (comprehensive metric library) Evaluation metrics
array.py Array C++ array wrapper
block_format_writer.py BlockFormatWriter Block format file writer
tensorio.py TensorIO Tensor serialization I/O
util.py (utility functions) Checkpoint mgmt, feature conversion
errors.py EarlyStopError, CheckpointNotFoundError Custom exceptions

C++ layer (twml/libtwml/, 21 files, 112K chars + 8 internal files, 34K chars):

  • Native implementations for data format parsing, array operations, and performance-critical paths
  • Exposed to Python via the Array and BlockFormatWriter wrapper classes

Common utilities (twml/twml_common/, 3 files, 1.8K chars):

  • PartitionInitializer — Keras initializer from numpy arrays
  • serialize / deserialize — object serialization helpers
  • create_sparse_tensor / create_reference_input — sparse tensor construction

Architecture Deep Dive: Follow Recommendations Service

The Follow Recommendations Service is the largest service by model complexity:

Common models (follow-recommendations-service/common/src/main/scala/.../common/models/, 54 files, 78K chars): Define the data model for recommendation candidates, scores, signals, and display contexts.

Candidate sources (16+ algorithms): Each in its own directory under common/candidate_sources/, with dedicated README explaining the algorithm, data sources, and parameters.

Ranking pipeline:

  1. Candidates from all sources are unified
  2. Feature hydration from RealGraph, Feature Store, social graph
  3. Multi-tower MLP model scores candidates (trained weekly on Profile Sidebar impression data)
  4. Filtering by safety, dedup, business rules
  5. Results published to Manhattan for serving

Controllers (follow-recommendations-service/server/src/main/scala/.../controllers/, 5 files, 8.5K chars): Handle request routing, response assembly, and flow orchestration.

Architecture Deep Dive: TweetyPie

TweetyPie is the tweet storage and hydration service — one of the largest services in the codebase:

  • Handlers (tweetypie/server/src/main/scala/.../handler/, 49 files, 91K chars): Tweet CRUD operations, media handling, URL resolution, safety checks
  • Config (tweetypie/server/src/main/scala/.../config/, 22 files, 245K chars): Service configuration, feature switches, dependency wiring
  • Core (tweetypie/server/src/main/scala/.../core/, 15 files, 33K chars): Core tweet model, hydration, filtering
  • Observers (tweetypie/server/src/main/scala/.../service/observer/, 11 files, 30K chars): Per-operation metrics and tracing
  • Servo subsystem: Request handling, repository pattern, JSON serialization, decider integration

Architecture Deep Dive: VisibilityLib

VisibilityLib evaluates content visibility rules:

  • Models (visibilitylib/src/main/scala/.../visibility/models/, 24 files, 126K chars): Content labels, visibility actions, rule outcomes, abuse types, media labels, safety levels
  • Features (visibilitylib/src/main/scala/.../visibility/features/, 4 files, 15K chars): Feature definitions for rule evaluation
  • Rules (visibilitylib/src/main/scala/.../visibility/rules/): Rule definitions and evaluation logic
  • Builders (visibilitylib/src/main/scala/.../visibility/builder/): Rule context construction

Architecture Deep Dive: Push Service (Notifications)

The notification system uses a four-stage pipeline:

  1. Candidate generation — multiple sources produce notification candidates
  2. Light ranking — fast MLP pre-filter (pushservice/src/main/python/models/light_ranking/)
  3. Heavy ranking — ClemNet multi-task model (pushservice/src/main/python/models/heavy_ranking/)
  4. Quality control — policy predicates

Heavy ranker architecture (ClemNet):

class ClemNet(tf.keras.layers.Layer):
    # Multi-block architecture with:
    # - KerasConv1D layers (1D convolution on feature groups)
    # - ChannelWiseDense layers (per-channel dense projection)
    # - ResidualLayer connections
    # - Block2 modules combining conv + dense + residual

Configuration via Pydantic-style params: ClemNetParams, BlockParams, ConvParams, DenseParams, TopLayerParams.

Predicate system (pushservice/src/main/scala/.../pushservice/predicate/event/, 1 file, 6.3K chars): Event-based filtering predicates for notification quality control.

Config (pushservice/src/main/scala/.../pushservice/config/, 5 files, 119K chars): The largest config module in the codebase, containing comprehensive notification pipeline configuration.

Architecture Deep Dive: SimClusters

SimClusters maps users and content into a shared topic embedding space:

  • Summingbird common (src/scala/com/twitter/simclusters_v2/summingbird/common/, 14 files, 51K chars): Real-time aggregation of cluster membership
  • Scalding embedding (src/scala/com/twitter/simclusters_v2/scalding/embedding/common/, 4 files, 37K chars): Batch embedding generation
  • Scalding common (src/scala/com/twitter/simclusters_v2/scalding/common/, 4 files, 14.6K chars): Shared Scalding utilities
  • Common (src/scala/com/twitter/simclusters_v2/common/, 11 files, 43K chars): Core cluster models and utilities
  • Scio pipelines: BigQuery generation and multi-type graph processing

Architecture Deep Dive: Earlybird Internals

Earlybird's search index architecture (from src/java/com/twitter/search/):

  • Core (core/earlybird/): Inverted index, posting lists, term dictionaries (FST and MPH), column-stride field indexes, facet counting
  • Config (earlybird/config/, 7 files, 26K chars + earlybird/common/config/, 2 files, 25K chars): Schema definitions, tier configurations
  • Ingester (search/ingester/pipeline/app/, 4 files, 13K chars): Kafka-to-index pipeline
  • Earlybird Root (earlybird_root/common/, 9 files, 38K chars + earlybird_root/config/, 1 file, 1.5K chars): Request routing and response merging across partitions
  • Relevance (search/common/relevance/, config + features): Search result scoring and feature extraction
  • Schema (search/common/schema/, 9 files, 62K chars): Tweet field definitions, analyzers, and index mappings

Code Patterns and Conventions

Dependency injection: All services use Google Guice via Finatra's module system. Services declare dependencies as Module sequences.

RPC pattern: Thrift-based RPC with Finagle. Services define Thrift IDL in thrift/ directories, generate Scala/Java stubs, and implement controllers.

Pipeline pattern: Product Mixer's step-based pipeline with fail-open policies, quality factors, and arrow-based execution (Twitter's Stitch library).

Configuration pattern: YAML configs in resources/config/ directories, loaded by service-specific config modules (Scala objects/classes).

Testing pattern: Test files co-located with source in parallel test/ directories. Unified User Actions includes test configs for client validation.

Error handling:

  • Custom exception types (EarlyStopError, CheckpointNotFoundError, InvalidStepStateException)
  • Fail-open policies for non-critical pipeline stages
  • Stitch-based error propagation in Product Mixer

Testing Strategy

  • Unit tests: Standard Scala/Java test frameworks, co-located in src/test/
  • Integration tests: Service-level tests using Finatra's testing framework
  • Load tests: ANN load test framework with configurable QPS, duration, and parameter grid search
  • ML model evaluation: twml's eval.steps and eval.period for online evaluation during training
  • CI: Minimal (ci/ci.sh exits 0); real validation through Bazel test targets

Potential Improvements

Based on code analysis:

  1. CI pipeline — The ci/ci.sh script is a no-op. A real CI pipeline running ./bazel test //... on key targets would prevent regressions.
  2. Documentation — repo_docs.cbf returned 0 files at the root level. A root-level README summarizing the architecture would help new contributors.
  3. Dependency versions — Navi pins specific Git tags for ort crate; upgrading to ONNX Runtime 1.15+ would bring performance improvements.
  4. Python version — twml and the Dockerfile pin Python 3.7, which reached end-of-life in June 2023. Migration to 3.10+ is recommended.
  5. Configuration — Service configs are scattered across 12+ locations with no unified schema. A shared configuration framework would reduce duplication.
  6. Feature Store coupling — Multiple services depend on the internal Feature Store client. Abstracting this behind an interface would improve testability.

Contributing

The repository is read-only (archived). To study or adapt the code:

  1. Fork the repository
  2. Build individual services using Bazel or Cargo
  3. Service-specific READMEs exist in many subsystem directories (especially follow-recommendations-service/common/src/main/scala/.../candidate_sources/)
  4. The ANN subsystem has the most complete internal documentation with README.rst and README.md files

9. Integration Points

Inter-Service Communication

All services communicate via Thrift RPC over Finagle with mTLS:

From To Protocol Purpose
Home Mixer Earlybird Thrift In-network tweet retrieval
Home Mixer CR-Mixer Thrift Out-of-network candidates
Home Mixer Timeline Ranker Thrift Candidate scoring
Home Mixer VisibilityLib Library Content filtering
Timeline Ranker Graph Feature Service Thrift Graph features
Timeline Ranker User Signal Service Thrift User signals
Follow Recs RealGraph Thrift/Data Engagement graph
Follow Recs Feature Store Thrift Feature hydration
Push Service Navi gRPC Model inference
All Services Manhattan Thrift Key-value storage
All Services Kafka Protocol Event streaming
Batch Jobs HDFS Protocol Data storage

Event Streaming (Kafka Topics)

Unified User Actions (UUA) standardizes event tracking across all surfaces:

  • Adapters (unified_user_actions/adapter/): Convert product-specific events to UUA format
  • Kafka serialization (unified_user_actions/kafka/): Custom Kafka SerDe with internal type handling
  • Enrichment (unified_user_actions/enricher/): Post-processing enrichment of UUA events
  • Client (unified_user_actions/client/): Client library with environment-specific config (staging, production)

Embedding Infrastructure

Component Role
Representation Manager Stores and versions embeddings, handles migration between versions
Representation Scorer Computes similarity between embedding pairs
Feature Store Serves embeddings as features for model inference
SimClusters Generates topic embeddings via batch Scalding/Scio jobs
ANN Service Indexes embeddings for nearest-neighbor queries

The Representation Manager's migration module (representation-manager/server/src/main/scala/.../migration/, 1 file, 34K chars) handles version transitions for the embedding storage layer.