Full Width [alt+shift+f] Shortcuts [alt+shift+k]
Sign Up [alt+shift+s] Log In [alt+shift+l]
38

An entire Social Network in 1.6GB (GraphD Part 2)

from Jaz's Blog [alt+shift+b] in AI

In Part 1 of this series, we tried to answer the question “who do you follow who also follows user B” in Bluesky, a social network with millions of users and hundreds of millions of follow relationships. At the conclusion of the post, we’d developed an in-memory graph store for the network that uses HashMaps and HashSets to keep track of the followers of every user and the set of users they follow, allowing bidirectional lookups, intersections, unions, and other set operations for combining social graph data. I received some helpful feedback after that post where several people pointed me towards Roaring Bitmaps as a potential improvement on my implementation. They were right, Roaring Bitmaps would be an excellent fit for my Graph service, GraphD, and could also provide me with a much needed way to quickly persist and load the Graph data to and from disk on startup, hopefully reducing the startup time of the service. What are Bitmaps? If you just want to dive into the Roaring Bitmap spec, you can read the paper here, but it might be easier to first talk about bitmaps in general. You can think of a bitmap as a vector of one-bit values (like booleans) that let you encode a set of integer values. For instance, say we have 10,000 users on our website and want to keep track of which users have validated their email addresses. We could do this by creating a list of the uint32 user IDs of each user, in which case if all 10,000 users have validated their emails we’re storing 10k * 32 bits = 40KB. Or, we could create a vector of single-bit values that’s 10,000 bits long (10k / 8 = 1.25KB), then if a user has confirmed their email we can set the value at the index of their UID to 1. If we want to create a list of all the UIDs of validated accounts, we can walk the vector and record the index of each non-zero bit. If we want to check if user n has validated their email, we can do a O(1) lookup in the bitmap by loading the bit at index n and checking if it’s set. When Bitmaps...
20th Apr 2024

Stay updated

Get a weekly newsletter with the top 5 articles worth reading every week.

More from Jaz's Blog

Reverse Twins
2nd Oct 2025 • 24 votes
Turning Billions of Strings into Integers Every Second Without Collisions

I’ve recently started building a POC of a Redis RESP3 Wire Compatible Key/Value Database built on FoundationDB with @calabro.io and though it’s rather early, it’s already spawned a fun distributed systems problem that I thought would be interesting to share. Previously I’ve written about how I implemented a Graph DB via Roaring Bitmaps, representing relations as a bidirectional pair of sets. To support such use-cases in this new database, we’d like to represent sets of keys such that you can perform boolean operations on them (intersection, union, difference) relatively quickly even for very large sets (with millions of members). Supporting Larger Keys In the original Graph DB, we were representing user DID strings as uint32 UIDs to allow us to store millions of edge lists in very little space (e.g. the set of users who follow bsky.app) while being able to perform boolean operations between lists quickly (using Roaring Bitmaps’ parallel boolean operators). Since we were graphing follows, blocks, and other such User-to-User relationships, there was a practical maximum for the total number of user IDs in the low billions. We’ve continued exploring objects and relationships we’d like to represent as a Graph, and have realized that if we wanted to store e.g. the URIs of all posts a user has liked so we can intersect it with other users’ likes, we’re going to need a bigger keyspace! There are well over 15 Billion records in the AT Proto Ecosystem, each with a unique AT URI! Now our desired keyspace is much larger than can be represented by uint32 values and so we need to expand to uint64. Easy enough, let’s use the uint64 flavor of Roaring Bitmaps and simply intern URIs and User DIDs as uint64s, problem solved, right? Not quite… Interning Many Things at Once The AT Proto Firehose has hit historic peak traffic of over 1,500 evt/sec. We want to design a system that will handle many times more scale than we’ve ever seen in reality. This means designing for 10x or 100x would require us to be able to intern 15k to 150k new URIs per second into uint64 integers. Sounds easy enough, what’s the holdup? Well, in FoundationDB we’re able to use Transactions to do things like atomically increment a sequence safely when many other threads may be trying to do the same thing. This is simple enough to do in Go, we can just toss together a little helper function to acquire a new UID for our string: func (s *server) allocateNewUID(span trace.Span, tx fdb.Transaction) (uint64, error) { var newUID uint64 val, err := tx.Get(fdb.Key("last_uid")).Get() if err != nil { return 0, return fmt.Errorf("failed to get last UID: %w", err) } if len(val) == 0 { newUID = 1 // start from 1 } else { lastUID, err := strconv.ParseUint(string(val), 10, 64) if err != nil { return 0, return fmt.Errorf("failed to parse last UID: %w", err) } newUID = lastUID + 1 } tx.Set(fdb.Key("last_uid"), []byte(strconv.FormatUint(newUID, 10))) return newUID, nil } This function gets called from a fdb.Transaction which gets assigned a Transaction ID, then stages its changes, then tries to commit them. In FoundationDB, if your transaction is reading or modifying data written to by a different Transaction that finishes while you’re in-progress, your Transaction is thrown out and must be retried. For our UID assignment use-case, this is pretty problematic. We want to assign hundreds of thousands of new UIDs per second but if they’re all modifying the same key, concurrent transactions will constantly run into contention on the same data and will be forced to retry over and over again. This problem gets worse the more concurrent transactions you have trying to read from or write to the same key. Even if we stick to sequential access, if it takes ~5-10ms to assign a UID, we can only assign ~100-200 UIDs per second, nowhere near the throughput we need to support. How can we get past this problem and allow us to give strings unique uint64 UIDs in a high throughput and highly concurrent manner? Attempt #1: xxHash My first attempt to solve this problem was to try something that required no coordination and hash the string keys into uint64s using xxHash. xxHash is a non-cryptographic hash algorithm that supports incredibly high throughput (dozens of GB/sec) and can produce 64 bit unsigned integer hashes of strings trivially. Implementing this would look something like: Hash the incoming string key Lookup the uint64 UID to see if we’ve already assigned it to a string Reject the transaction if there’s a collision and give up Store the key in the UID map and the UID in the key map Use the UID for anything else we need While the uint64 keyspace is plenty large for our needs assuming we distribute evenly among the whole space, using a hashing algorithm with no coordination means there’s room for collisions and thus we’d need some additional logic (potentially by bucketing the keys somehow). Consulting the Birthday Problem we can see that a keyspace with 64 bit hashes has a >50% chance of containing a single collision when we have only ~5 billion keys in the set! That’s barely more keys than we can cram into a uint32 and definitely won’t suffice for the number of keys we expect to be storing! So, xxHash, while nice and coordination-free is probably not going to be the solution we need. What else can we do? Attempt #2: Billions of Sequences Incrementing one sequence is clearly not an option because we can only increment a single sequence ~100-200 times per second, but what if we instead had more than one sequence? Roaring Bitmaps managed to make highly efficient bitmap representations by breaking up a uint32 keyspace into a uint16-wide set of uint16-wide keyspaces. Can we do something similar here? Here’s an idea, what if we had just over 4 billion difference sequences and just picked one at random when we needed to assign a UID? Since we’re constructing our UIDs as a uint64, we can split the full UID into a pair of uint32s where the most-significant-bits are used to identify the sequence ID and the least-significant-bits are used to identify the value assigned to the UID within the sequence. So in our implementation, we get ~4.3 Billion sequence IDs that each have ~4.3 Billion incrementing values. As an example, if we were to randomly select Sequence ID 37 and then we increment that sequence to the value 5, we’d assemble the ID as 37<<32 + 5 which looks like 158,913,789,952 + 5 -> 158,913,789,957. Looking at the next Seuqence ID, we’d see 38 which, when left shifted by 32 gives us 163,208,757,248. You can see there’s a gap of ~4.3 billion values between the first UID assigned by each Sequence ID. Assuming we can increment a single sequence ~100 times per second with contention, we’re able to mint 430 Billion new UIDs per second without locking up (assuming the cluster can keep up). Storing ~4.3 billion sequences may be a bit expensive, but thankfully this strategy can scale up and down by picking a larger or smaller prefix size. If we only wanted to store say, ~16k sequences, we can pick a 14 bit prefix instead of a 32 bit prefix and then use a 50 bit sequence number. That spreads the load across 2^14 sequence IDs and significantly reduces storage requirements for Sequences. What does this look like in code? Well, it’s honestly not very complex! const uidSequencePrefix = "uid_sequence/" func (s *server) allocateNewUID(tx fdb.Transaction) (uint64, error) { // sequenceNum is the random uint32 sequence we are using for this allocation var sequenceNum uint32 var sequenceKey string // assignedUID is the uint32 within the sequence we will assign var assignedUID uint32 // Try up to 5 times to find a sequence that is not exhausted for range 5 { // Pick a random uint32 as the sequence we will be using for this UID sequenceNum = rand.Uint32() sequenceKey = fmt.Sprintf("%s%d", uidSequencePrefix, sequenceNum) val, err := tx.Get(fdb.Key(sequenceKey)).Get() if err != nil { return 0, fmt.Errorf("failed to get last UID: %w", err) } if len(val) == 0 { assignedUID = 1 // Start each sequence at 1 } else { lastUID, err := strconv.ParseUint(string(val), 10, 32) if err != nil { return 0, fmt.Errorf("failed to parse last UID: %w", err) } // If we have exhausted this sequence, pick a new random sequence if lastUID >= 0xFFFFFFFF { continue } assignedUID = uint32(lastUID) + 1 } } // If we failed to find a sequence after 5 tries, return an error if assignedUID == 0 { return 0, fmt.Errorf("failed to allocate new UID after 5 attempts") } // Assemble the 64-bit UID from the sequence ID and assigned UID newUID := (uint64(sequenceNum) << 32) | uint64(assignedUID) // Store the assigned UID back to the sequence key for the next allocation tx.Set(fdb.Key(sequenceKey), []byte(strconv.FormatUint(uint64(assignedUID), 10))) // Return the full 64-bit UID return newUID, nil } And there we go! We can now intern billions of strings per second with little to no contention in a distributed system while completely avoiding collisions and making full use of our keyspace! Conclusion Often times when designing distributed systems, patterns and strategies you see in seemingly unrelated libraries can inspire an elegant solution to the problem at hand. In the case of distributed, high-throughput string interning, horizontal scaling can be achieved by breaking up one large keyspace that requires strict coordination into billions of smaller keyspaces that can be randomly load-balanced across. Both patterns used in this technique are present elsewhere: Breaking up a large keyspace into a bunch of smaller keyspaces is present in Roaring Bitmaps (among other systems) Letting randomness and large numbers spread out resource contention is present in many load balancing systems This is one of my favorite parts of growing as an engineer: the more systems and strategies you familiarize yourself with, the more material you have to draw from when designing something new. Personal News A bit of personal news for y’all if you made it this far. Today is my last day as a member of the Bluesky team! The past 2+ years building out Bluesky’s Infrastructure and Platform team and scaling Bluesky from 100,000 -> 40,000,000 users have been the most intense and rewarding years of my life. I don’t have the words to express how much I’ve valued my time on the team and how much I care for the people I’ve worked with in what feels like a decade of real time. I’ve got some new adventures ahead and am excited to be embarking on a new journey within the next month (still building large-scale infrastructure, don’t worry). I plan to continue being involved in the AT Proto Community and to contribute to some cool projects other folks on the Bluesky team are working on from the FOSS space (like KVDB). To the team, I wish you all the best and will dearly miss getting to work with you all every day, but nothing lasts forever and I will always cherish the time I got to spend building an incredible platform with incredible people. If you’re interested in joining a world-class team doing important work, check out Bluesky’s open job listings here. There should be a new role opening up for a seasoned Go Engineer on the Platform team soon!

26th Sep 2025 • 1 votes
When Imperfect Systems are Good, Actually: Bluesky's Lossy Timelines

Often when designing systems, we aim for perfection in things like consistency of data, availability, latency, and more. The hardest part of system design is that it’s difficult (if not impossible) to design systems that have perfect consistency, perfect availability, incredibly low latency, and incredibly high throughput, all at the same time. Instead, when we approach system design, it’s best to treat each of these properties as points on different axes that we balance to find the “right fit” for the application we’re supporting. I recently made some major tradeoffs in the design of Bluesky’s Following Feed/Timeline to improve the performance of writes at the cost of consistency in a way that doesn’t negatively affect users but reduced P99s by over 96%. Timeline Fanout When you make a post on Bluesky, your post is indexed by our systems and persisted to a database where we can fetch it to hydrate and serve in API responses. Additionally, a reference to your post is “fanned out” to your followers so they can see it in their Timelines. This process involves looking up all of your followers, then inserting a new row into each of their Timeline tables in reverse chronological order with a reference to your post. When a user loads their Timeline, we fetch a page of post references and then hydrate the posts/actors concurrently to quickly build an API response and let them see the latest content from people they follow. The Timelines table is sharded by user. This means each user gets their own Timeline partition, randomly distributed among shards of our horizontally scalable database (ScyllaDB), replicated across multiple shards for high availability. Timelines are regularly trimmed when written to, keeping them near a target length and dropping older post references to conserve space. Hot Shards in Your Area Bluesky currently has around 32 Million Users and our Timelines database is broken into hundreds of shards. To support millions of partitions on such a small number of shards, each user’s Timeline partition is colocated with tens of thousands of other users’ Timelines. Under normal circumstances with all users behaving well, this doesn’t present a problem as the work of an individual Timeline is small enough that a shard can handle the work of tens of thousands of them without being heavily taxed. Unfortunately, with a large number of users, some of them will do abnormal things like… well… following hundreds of thousands of other users. Generally, this can be dealt with via policy and moderation to prevent abusive users from causing outsized load on systems, but these processes take time and can be imperfect. When a user follows hundreds of thousands of others, their Timeline becomes hyperactive with writes and trimming occurring at massively elevated rates. This load slows down the individual operations to the user’s Timeline, which is fine for the bad behaving user, but causes problems to the tens of thousands of other users sharing a shard with them. We typically call this situation a “Hot Shard”: where some resident of a shard has “hot” data that is being written to or read from at much higher rates than others. Since the data on the shard is only replicated a few times, we can’t effectively leverage the horizontal scale of our database to process all this additional work. Instead, the “Hot Shard” ends up spending so much time doing work for a single partition that operations to the colocated partitions slow down as well. Stacking Latencies Returning to our Fanout process, let’s consider the case of Fanout for a user followed by 2,000,000 other users. Under normal circumstances, writing to a single Timeline takes an average of ~600 microseconds. If we sequentially write to the Timelines of our user’s followers, we’ll be sitting around for 20 minutes at best to Fanout this post. If instead we concurrently Fanout to 1,000 Timelines at once, we can complete this Fanout job in ~1.2 seconds. That sounds great, except it oversimplifies an important property of systems: tail latencies. The average latency of a write is ~600 microseconds, but some writes take much less time and some take much more. In fact, the P99 latency of writes to the Timelines cluster can be as high as 15 milliseconds! What does this mean for our Fanout? Well, if we concurrently write to 1,000 Timelines at once, statistically we’ll see 10 writes as slow as or slower than 15 milliseconds. In the case of timelines, each “page” of followers is 10,000 users large and each “page” must be fanned out before we fetch the next page. This means that our slowest writes will hold up the fetching and Fanout of the next page. How does this affect our expected Fanout time? Each “page” will have ~100 writes as slow as or slower than the P99 latency. If we get unlucky, they could all stack up on a single routine and end up slowing down a single page of Fanout to 1.5 seconds. In the worst case, for our 2,000,000 Follower celebrity, their post Fanout could end up taking as long as 5 minutes! That’s not even considering P99.9 and P99.99 latencies which could end up being >1 second, which could leave us waiting tens of minutes for our Fanout job. Now imagine how bad this would be for a user with 20,000,000+ Followers! So, how do we fix the problem? By embracing imperfection, of course! Lossy Timelines Imagine a user who follows hundreds of thousands of others. Their Timeline is being written to hundreds of times a second, moving so fast it would be humanly impossible to keep up with the entirety of their Timeline even if it was their full-time job. For a given user, there’s a threshold beyond which it is unreasonable for them to be able to keep up with their Timeline. Beyond this point, they likely consume content through various other feeds and do not primarily use their Following Feed. Additionally, beyond this point, it is reasonable for us to not necessarily have a perfect chronology of everything posted by the many thousands of users they follow, but provide enough content that the Timeline always has something new. Note in this case I’m using the term “reasonable” to loosely convey that as a social media service, there must be a limit to the amount of work we are expected to do for a single user. What if we introduce a mechanism to reduce the correctness of a Timeline such that there is a limit to the amount of work a single Timeline can place on a DB shard. We can assert a reasonable limit for the number of follows a user should have to have a healthy and active Timeline, then increase the “lossiness” of their Timeline the further past that limit they go. A loss_factor can be defined as min(reasonable_limit/num_follows, 1) and can be used to probabilistically drop writes to a Timeline to prevent hot shards. Just before writing a page in Fanout, we can generate a random float between 0 and 1, then compare it to the loss_factor of each user in the page. If the user’s loss_factor is smaller than the generated float, we filter the user out of the page and don’t write to their Timeline. Now, users all have the same number of “follows worth” of Fanout. For example with a reasonable_limit of 2,000, a user who follows 4,000 others will have a loss_factor of 0.5 meaning half the writes to their Timeline will get dropped. For a user following 8,000 others, their loss factor of 0.25 will drop 75% of writes to their Timeline. Thus, each user has a effective ceiling on the amount of Fanout work done for their Timeline. By specifying the limits of reasonable user behavior and embracing imperfection for users who go beyond it, we can continue to provide service that meets the expectations of users without sacrificing scalability of the system. Aside on Caching We write to Timelines at a rate of more than one million times a second during the busy parts of the day. Looking up the number of follows of a given user before fanning out to them would require more than one million additional reads per second to our primary database cluster. This additional load would not be well received by our database and the additional cost wouldn’t be worth the payoff for faster Timeline Fanout. Instead, we implemented an approach that caches high-follow accounts in a Redis sorted set, then each instance of our Fanout service loads an updated version of the set into memory every 30 seconds. This allows us to perform lookups of follow counts for high-follow accounts millions of times per second per Fanount service instance. By caching values which don’t need to be perfect to function correctly in this case, we can once again embrace imperfection in the system to improve performance and scalability without compromising the function of the service. Results We implemented Lossy Timelines a few weeks ago on our production systems and saw a dramatic reduction in hot shards on the Timelines database clusters. In fact, there now appear to be no hot shards in the cluster at all, and the P99 of a page of Fanout work has been reduced by over 90%. Additionally, with the reduction in write P99s, the P99 duration for a full post Fanout has been reduced by over 96%. Jobs that used to take 5-10 minutes for large accounts now take <10 seconds. Knowing where it’s okay to be imperfect lets you trade consistency for other desirable aspects of your systems and scale ever higher. There are plenty of other places for improvement in our Timelines architecture, but this step was a big one towards improving throughput and scalability of Bluesky’s Timelines. If you’re interested in these sorts of problems and would like to help us build the core data services that power Bluesky, check out this job listing. If you’re interested in other open positions at Bluesky, you can find them here.

19th Feb 2025 • 63 votes
Emoji Griddle
30th Oct 2024 • 35 votes
Jetstream: Shrinking the AT Proto Firehose by >99%

Bluesky recently saw a massive spike in activity in response to Brazil’s ban of Twitter. As a result, the AT Proto event firehose provided by Bluesky’s Relay at bsky.network has increased in volume by a huge amount. The average event rate during this surge increased by ~1,300%. Before this new surge in activity, the firehose would produce around 24 GB/day of traffic. After the surge, this volume jumped to over 232 GB/day! Keeping up with the full, verified firehose quickly became less practical on cheap cloud infrastructure with metered bandwidth. To help reduce the burden of operating bots, feed generators, labelers, and other non-verifying AT Proto services, I built Jetstream as an alternative, lightweight, filterable JSON firehose for AT Proto. How the Firehose Works The AT Proto firehose is a mechanism used to keep verified, fully synced copies of the repos of all users. Since repos are represented as Merkle Search Trees, each firehose event contains an update to the user’s MST which includes all the changed blocks (nodes in the path from the root to the modified leaf). The root of this path is signed by the repo owner, and a consumer can keep their copy of the repo’s MST up-to-date by applying the diff in the event. For a more in-depth explanation of how Merkle Trees are constructed, check out this explainer. Practically, this means that for every small JSON record added to a repo, we also send along some number of MST blocks (which are content-addressed hashes and thus very information-dense) that are mostly useful for consumers attempting to keep a fully synced, verified copy of the repo. You can think of this as the difference between cloning a git repo v.s. just grabbing the latest version of the files without the .git folder. In this case, the firehose effectively streams the diffs for the repository with commits, signatures, and metadata, which is inherently heavier than a point-in-time checkout of the repo. Because firehose events with repo updates are signed by the repo owner, they allow a consumer to process events from any operator without having to trust the messenger. This is the “Authenticated” part of the Authenticated Transfer (AT) Protocol and is crucial to the correct functioning of the network. That being said, of the hundreds of consumers of Bluesky’s production Relay, >90% of them are building feeds, bots, and other tools that don’t keep full copies of the entire network and don’t verify MST operations at all. For these consumers, all they actually process is the JSON records created, updated, and deleted in each event. If consumers already trust the provider to do validation on their end, they could get by with a much more lightweight data stream. How Jetstream Works Jetstream is a streaming service that consumes an AT Proto com.atproto.sync.subscribeRepos stream and converts it into lightweight, friendly JSON. If you want to try it out yourself, you can connect to my public Jetstream instance and view all posts on Bluesky in realtime: $ websocat "wss://jetstream2.us-east.bsky.network/subscribe?wantedCollections=app.bsky.feed.post" Note: the above instance is operated by Bluesky PBC and is free to use, more instances are listed in the official repo Readme Jetstream converts the CBOR-encoded MST blocks produced by the AT Proto firehose and translates them into JSON objects that are easier to interface with using standard tooling available in programming languages. Since Repo MSTs only contain records in their leaf nodes, this means Jetstream can drop all of the blocks in an event except for those of the leaf nodes, typically leaving only one block per event. In reality, this means that Jetstream’s JSON firehose is nearly 1/10 the size of the full protocol firehose for the same events, but lacks the verifiability and signatures included in the protocol-level firehose. Jetstream events end up looking something like: { "did": "did:plc:eygmaihciaxprqvxpfvl6flk", "time_us": 1725911162329308, "type": "com", "commit": { "rev": "3l3qo2vutsw2b", "type": "c", "collection": "app.bsky.feed.like", "rkey": "3l3qo2vuowo2b", "record": { "$type": "app.bsky.feed.like", "createdAt": "2024-09-09T19:46:02.102Z", "subject": { "cid": "bafyreidc6sydkkbchcyg62v77wbhzvb2mvytlmsychqgwf2xojjtirmzj4", "uri": "at://did:plc:wa7b35aakoll7hugkrjtf3xf/app.bsky.feed.post/3l3pte3p2e325" } }, "cid": "bafyreidwaivazkwu67xztlmuobx35hs2lnfh3kolmgfmucldvhd3sgzcqi" } } Each event lets you know the DID of the repo it applies to, when it was seen by Jetstream (a time-based cursor), and up to one updated repo record as serialized JSON. Check out this 10 second CPU profile of Jetstream serving 200k evt/sec to a local consumer: By dropping the MST and verification overhead by consuming from relay we trust, we’ve reduced the size of a firehose of all events on the network from 232 GB/day to ~41GB/day, but we can do better. Jetstream and zstd I recently read a great engineering blog from Discord about their use of zstd to compress websocket traffic to/from their Gateway service and client applications. Since Jetstream emits marshalled JSON through the websocket for developer-friendliness, I figured it might be a neat idea to see if we could get further bandwidth reduction by employing zstd to compress events we send to consumers. zstd has two basic operating modes, “simple” mode and “streaming” mode. Streaming Compression At first glance, streaming mode seems like it’d be a great fit. We’ve got a websocket connection with a consumer and streaming mode allows the compression to get more efficient over the lifetime of the connection. I went and implemented a streaming compression version of Jetstream where a consumer can request compression when connecting and will get zstd compressed JSON sent as binary messages over the socket instead of plaintext. Unfortunately, this had a massive impact on Jetstream’s server-side CPU utilization. We were effectively compressing every message once per consumer as part of their streaming session. This was not a scalable approach to offering compression on Jetstream. Additionally, Jetstream stores a buffer of the past 24 hours (configurable) of events on disk in PebbleDB to allow consumers to replay events before getting transitioned into live-tailing mode. Jetstream stores serialized JSON in the DB, so playback is just shuffling the bytes into the websocket without having to round-trip the data into a Go struct. When we layer in streaming compression, playback becomes significantly more expensive because we have to compress outgoing events on-the-fly for a consumer that’s catching up. In real numbers, this increased CPU usage of Jetstream by 23% while lowering the throughput of playback from ~200k evt/sec to ~28k evt/sec for a single local consumer. When in streaming mode, we can’t leverage the bytes we compress for one consumer and reuse them for another consumer because zstd’s streaming context window may not be in sync between the two consumers. They haven’t received exactly the same data in the session so the clients on the other end don’t have their state machines in the same state. Since streaming mode’s primary advantage is giving us eventually better efficiency as the encoder learns about the data, what if we just taught the encoder about the data at the start and compress each message statelessly? Dictionary Mode zstd offers a mechanism for initializing an encoder/decoder with pre-optimized settings by providing a dictionary trained on a sample of the data you’ll be encoding/decoding. Using this dictionary, zstd essentially uses it’s smallest encoded representations for the most frequently seen patterns in the sample data. In our case, where we’re compressing serialized JSON with a common event shape and lots of common property names, training a dictionary on a large number of real events should allow us to represent the common elements among messages in the smallest number of bytes. For take two of Jetstream with zstd, let’s to use a single encoder for the whole service that utilizes a custom dictionary trained on 100,000 real events. We can use this encoder to compress every event as we see it, before persisting and emitting it to consumers. Now we end up with two copies of every event, one that’s just serialized JSON, and one that’s statelessly compressed to zstd using our dictionary. Any consumers that want compression can have a copy of the dictionary on their end to initialize a decoder, then when we broadcast the shared compressed event, all consumers can read it without any state or context issues. This requires the consumers and server to have a pre-shared dictionary, which is a major drawback of this implementation but good enough for our purposes. That leaves the problem of event playback for compression-enabled clients. An easy solution here is to just store the compressed events as well! Since we’re only sticking the JSON records into our PebbleDB, the actual size of the 24 hour playback window is <8GB with sstable compression. If we store a copy of the JSON serialized event and a copy of the zstd compressed event, this will, at most, double our storage requirements. Then during playback, if the consumer requests compression, we can just shuffle bytes out of the compressed version of the DB into their socket instead of having to move it through a zstd encoder. Savings Running with a custom dictionary, I was able to get the average Jetstream event down from 482 bytes to just 211 bytes (~0.44 compression ratio). Jetstream allows us to live tail all posts on Bluesky as they’re posted for as little as ~850 MB/day, and we could keep up with all events moving through the firehose during the Brazil Twitter Exodus weekend for 18GB/day (down from 232GB/day). With this scheme, Jetstream is required to compress each event only once before persisting it to disk and emitting it to connected consumers. The CPU impact of these changes is significant in proportion to Jetstream’s incredibly light load but it’s a flat cost we pay once no matter how many consumers we have. (CPU profile from a 30 second pprof sample with 12 consumers live-tailing Jetstream) Additionally, with Jetstream’s shared buffer broadcast architecture, we keep memory allocations incredibly low and the cost per consumer on CPU and RAM is trivial. In the allocation profile below, more than 80% of the allocations are used to consume the full protocol firehose. The total resident memory of Jetstream sits below 16MB, 25% of which is actually consumed by the new zstd dictionary. To bring it all home, here’s a screenshot from the dashboard of my public Jetstream instance serving 12 consumers all with various filters and compression settings, running on a $5/mo OVH VPS. At our new baseline firehose activity, a consumer of the protocol-level firehose would require downloading ~3.16TB/mo to keep up. A Jetstream consumer getting all created, updated, and deleted records without compression enabled would require downloading ~400GB/mo to keep up. A Jetstream consumer that only cares about posts and has zstd compression enabled can get by on as little as ~25.5GB/mo, <99% of the full weight firehose. Feel free to join the conversation about Jetstream and zstd on Bluesky.

24th Sep 2024 • 41 votes

More in AI

A Modern Reorganization of Mathematics

[Everyone is doing guest posts these days, so here’s one about the Weil conjectures from (in alphabetical order) Bin Dong, Nailin Guan, Jiedong Jiang, Ruochuan Liu, Christian Merten, Xiangyu Pan, Tingxiao Shi, Bin Wu, Edison Xie and Wei Yang] We … Continue reading →

9 hours ago • 1 votes
20 years of blogging

20 years ago to this day, I started my new technical blog. I'd had a personal one for some time, but most of the stuff that happened there had already migrated to social media. I wanted somewhere to post the things that would only be of interest to my techier friends, and maybe of some use to anyone else that came across it. Things have changed a bit, but they've stayed the same in some ways. Earlier this year I finished my 48-part (!) LLM from scratch series, but it had predecessors -- the third post I made here was part one of a 13-part series where I worked through setting up automated backups for my homelab NAS, and then later on I spent a few months building a reverse proxy in C, not to mention the eight-month, ten-post series on fine-tuning LLMs. It does seem like there's some value to putting all of this online. I rarely check my logs and referrers, but people do still seem to be arriving here having searched for stuff that I've written about, and every now and then there's a kind "thanks for this!" comment left on an old post where I explained something I'd just learned. I wrote a bit more about the blog's history last year, and came to the conclusion that the best posts -- both for me to write, and as far as I could tell for other people to read -- were the ones where I wrote up a project that I'd been working on. I blogged about that in more detail, and it seemed to strike a chord on Hacker News; I think it still holds. Recently, Sean Goedecke suggested that the best blog posts are those where you write about things that you're in the process of learning, and I agree. You learn more than you would if you didn't write it up, and because things are fresh in your mind, you may well write more clearly about it than an actual expert in the subject might have done. Anyway, I'm going to carry on blogging. I'm working on my biggest LLM-related project so far (dozens of training runs, so my study aircon is getting quite the workout even with the weather turning colder), and look forward to posting about it later on this month. I hope it's at least as fun to read as it is to write!

16 hours ago • 1 votes
The missing quadrant in responses to AI

Announcing STABL: Societal Transformation and AI Bottlenecks Lab

20 hours ago • 1 votes
Fable 5.2 and Jagged AGI

General, often expert, and sometimes jagged

2 days ago • 1 votes
BAIR at CoRL 2026

The Conference on Robot Learning (CoRL) takes place November 9–12, 2026, in Austin, Texas. BAIR faculty, postdocs and students will be presenting research at various sessions, including an Early Career Keynote from Professor Negar Mehr. See below for the full schedule of sessions with BAIR members, including papers co-authored with collaborators at other universities and companies. h2 { border-bottom: 2px solid #003262; padding-bottom: 0.3rem; margin-bottom: 0.2rem; } .corl-day-sub { font-size: 0.8rem; color: #666; margin: 0 0 1em; } .corl-day-sub span + span::before { content: "·"; margin: 0 0.5em; color: #aaa; } .corl-session { display: grid; grid-template-columns: 7.5rem 1fr; gap: 1rem; padding: 1rem 0; border-top: 1px solid #eee; } .corl-session:first-of-type { border-top: 0; } .corl-session.corl-featured { background: #fffbf0; border-left: 3px solid #FDB515; padding-left: 0.8rem; } .corl-time { font-weight: 700; font-size: 0.9rem; line-height: 1.3; } .corl-time small { display: block; font-weight: 400; font-size: 0.7rem; color: #777; text-transform: uppercase; letter-spacing: 0.03em; } .corl-tag { display: inline-block; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.1rem 0.45rem; border-radius: 3px; background: #eef2f7; color: #003262; } .corl-tag.k-keynote { background: #FDB515; color: #1a1a1a; } .corl-tag.k-oral { background: #003262; color: #fff; } .corl-tag.k-spotlight { background: #3b7ea1; color: #fff; } .corl-tag.k-poster { background: #eef2f7; color: #003262; } .corl-tag.k-lbr { background: #e7f3ec; color: #145a32; } .corl-tag.k-workshop { background: #f1ecf7; color: #4a2a75; } .corl-session h3 { margin: 0.35rem 0 0.15rem; font-size: 1.05rem; } .corl-venue { font-size: 0.8rem; color: #666; margin: 0 0 0.6em; } .corl-chair { font-weight: 700; color: #333; } .corl-paper, .corl-appearance { margin: 0 0 0.9em; } .corl-paper h4, .corl-appearance h4 { font-size: 0.92rem; margin: 0 0 0.2em; line-height: 1.35; font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; font-weight: 700; } .corl-board { display: inline-block; font-size: 0.72rem; color: #555; border: 1px solid #ddd; border-radius: 3px; padding: 0 0.35rem; margin-bottom: 0.25em; } .corl-authors { font-size: 0.82rem; margin: 0 0 0.2em; line-height: 1.45; } .corl-also, .corl-sources, .corl-program, .corl-see { font-size: 0.75rem; color: #666; margin: 0 0 0.15em; } .corl-see { font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; font-style: italic; } .corl-talk { font-style: italic; margin: 0 0 0.2em; } .corl-appearance p { font-size: 0.85rem; margin: 0 0 0.2em; } .corl-organizers { margin: 0; padding-left: 1.1rem; } .corl-organizers li { margin-bottom: 0.5em; font-size: 0.88rem; } .corl-organizers p { margin: 0; font-size: 0.82rem; color: #444; } .corl-about { margin-top: 2.5em; border-top: 2px solid #003262; padding-top: 0.5em; font-size: 0.85rem; } .corl-about-links { font-family: 'Lato', 'Helvetica Neue', Helvetica, sans-serif; display: flex; flex-wrap: wrap; gap: 0.4rem 1.2rem; } @media (max-width: 40em) { .corl-stats { grid-template-columns: repeat(2, 1fr); } .corl-session { grid-template-columns: 1fr; gap: 0.3rem; } .corl-time small { display: inline; margin-left: 0.4em; } .corl-time { font-size: 1rem; } .corl-venue, .corl-also, .corl-sources, .corl-program, .corl-board, .corl-tag, .corl-time small, .corl-day-sub, .corl-stat small, .corl-nav-note, .corl-see { font-size: 0.8rem; } .corl-authors { font-size: 0.9rem; } } @media print { .corl-tools, .corl-status, .corl-nav, .corl-empty { display: none !important; } } November 9–12, 2026Austin, TexasAll times CST · UTC−6 33Main-conference papers 4Late-breaking results (LBR) posters 10Orals & spotlights3 orals · 7 spotlights 4Days of researchNovember 9–12 MonNov 9 TueNov 10 WedNov 11 ThuNov 12 Main conference Nov 9–11 · Workshops Nov 12 Times shown for oral and spotlight papers are session windows. Individual presentation order is not specified. Papers appear in both their talk and poster sessions. Paper inclusion: At least one author is affiliated with UC Berkeley; joint affiliations qualify. Faculty talks, session-chair roles and workshop participation are also included. Late-breaking results: Four late-breaking posters with Berkeley authors are listed so far. This list may grow as more late-breaking posters are confirmed. Find a paper or person Session typeAll sessionsKeynoteOralsSpotlightsPostersLate-breaking resultsWorkshops Reset Showing all sessionsUpdated November 8, 2026 No matching sessions. Try a surname, a shorter paper title, or reset the filters. Monday, November 9 Main conference10 papers + 3 LBR posters 9:00–9:30 AMCST Spotlight · S1 Generalist policies, memory and transfer Hilton Austin MEM: Multi-Scale Embodied Memory for Vision Language Action Models Marcel Torne, Karl Pertsch, Homer Walke, Kyle Vedder, Suraj Nair, Brian Ichter, Allen Z. Ren, Haohuan Wang, Jiaming Tang, Kyle Stachowicz, Karan Dhabalia, Michael Robert Equi, Quan Vuong, Jost Tobias Springenberg, Sergey Levine, Chelsea Finn, Danny Driess Also at Poster Session I · 5:00–6:30 PM · Poster 42 · JW Marriott Paper ↗ Diagnosing Compositional Generalization in Sequential Robot Tasks Yixiao Wang, Cheng-En Wu, Lingfeng Sun, Pengcheng Wang, Xiang Ji, Boyuan Liang, Guojian Zhan, Masayoshi Tomizuka Also at Poster Session I · 5:00–6:30 PM · Poster 115 · JW Marriott Paper ↗ 12:00–1:30 PMCST · LUNCH BREAK Late-breaking results · Posters Agentic Robotics Griffin · Level 2 · JW Marriott Austin Griffin board 119 · LBR #15 Scaling Online Exploration for Robot Agents Runhan Huang, Xiangcheng Zhang, Haoyu Chen, Yitong Li, Yen-Jen Wang, Bohan Lyu, Haotian Ye, Chuye Hong, Yixuan Wang, Chloe Su, Haoyu Xiong, Yangzhen Wu, Enze Xie, Travis Manderson, Stefano Ermon, Pieter Abbeel, Antonio Torralba, Dawn Song, Weirui Ye, Yilun Du Griffin board 120 · LBR #19 Reconstruct, Practice, Go Real: Guided Self-Improvement for Embodied Agents Yen-Jen Wang, Haozhe Jiang, Shuying Deng, Haoru Xue, Weirui Ye, Rocky Duan, Nika Haghtalab, S. Shankar Sastry, Pieter Abbeel, Haozhi Qi Also at Agentic Robotics workshop · Thursday, November 12 · 4:15–5:55 PM Griffin board 131 · LBR #54 Flip Anything with Agentic Robotics Self-Learning Shuangyu Xie, Kaiyuan Chen, Ken Goldberg GitHub ↗ Late-breaking results program ↗ 2:00–2:30 PMCST Keynote Early Career Keynote II Hilton Austin Session chair: Ken Goldberg Professor Negar Mehr How Can Robots Learn to Interact and Coordinate with Others? Session details ↗ 5:00–6:30 PMCST Posters Poster Session I JW Marriott Poster 42 MEM: Multi-Scale Embodied Memory for Vision Language Action Models Marcel Torne, Karl Pertsch, Homer Walke, Kyle Vedder, Suraj Nair, Brian Ichter, Allen Z. Ren, Haohuan Wang, Jiaming Tang, Kyle Stachowicz, Karan Dhabalia, Michael Robert Equi, Quan Vuong, Jost Tobias Springenberg, Sergey Levine, Chelsea Finn, Danny Driess Authors listed under Monday, Spotlight S1 Paper ↗ Poster 57 Large Video Planner Enables Generalizable Robot Control Boyuan Chen, Tianyuan Zhang, Haoran Geng, Caiyi Zhang, Peihao Li, Kiwhan Song, William T. Freeman, Jitendra Malik, Pieter Abbeel, Russ Tedrake, Vincent Sitzmann, Yilun Du Paper ↗ Poster 68 How to Peel with a Knife: Aligning Fine-Grained Manipulation with Human Preference Toru Lin, Shuying Deng, Zhao-Heng Yin, Pieter Abbeel, Jitendra Malik Paper ↗ Poster 97 HiRE: Hindsight Reward Editing for Policy Finetuning Haoyi Niu, Zhengtao Han, Yufeng Ji, Zhongyu Li, Koushil Sreenath Paper ↗ Poster 113 Scalable Behavior Cloning with Open Data, Training, and Evaluation Arthur Allshire, Himanshu Gaurav Singh, Ritvik Singh, Adam Rashid, Hongsuk Choi, David McAllister, Justin Yu, Yiyuan Chen, Huang Huang, Pieter Abbeel, Xi Chen, Rocky Duan, Phillip Isola, Jitendra Malik, Fred Shentu, Guanya Shi, Philipp Wu, Angjoo Kanazawa Paper ↗ Poster 115 Diagnosing Compositional Generalization in Sequential Robot Tasks Yixiao Wang, Cheng-En Wu, Lingfeng Sun, Pengcheng Wang, Xiang Ji, Boyuan Liang, Guojian Zhan, Masayoshi Tomizuka Authors listed under Monday, Spotlight S1 Paper ↗ Poster 142 AsyncVLA: An Asynchronous VLA for Fast and Robust Navigation on the Edge Noriaki Hirose, Catherine Glossop, Dhruv Shah, Sergey Levine Paper ↗ Poster 159 GLST: Global-Local Spatio-Temporal Memory Decomposition Framework for Online Chained-Goal Navigation Yousef Liang, Ryan Ardalan, Yarden Goraly, Chenhao Zhu, Jonas Frey, Claire Tomlin, Marco Pavone, S. Shankar Sastry Paper ↗ Poster 202 ENPIRE: Agentic Robot Policy Self-Improvement in the Real World Wenli Xiao, Jia Xie, Tonghe Zhang, Haotian Lin, Letian Fu, Haoru Xue, Jalen Lu, Yi Yang, Cunxi Dai, Zi Wang, Jimmy Wu, Guanzhi Wang, S. Shankar Sastry, Ken Goldberg, Linxi Fan, Yuke Zhu, Guanya Shi Paper ↗ Poster 225 Energy-Based Policy Orchestration Weirui Ye, Yen-Jen Wang, Elvis Hsieh, Zhiyang Dou, Shibo Zhao, Pieter Abbeel, Yilun Du, Leslie Pack Kaelbling, Tomás Lozano-Pérez Paper ↗ Tuesday, November 10 Main conference11 papers + 1 LBR poster 9:00–9:30 AMCST Oral · O4 Reinforcement learning and motion reasoning Hilton Austin Flow Policy Gradients for Robot Control Brent Yi, Hongsuk Choi, Himanshu Gaurav Singh, Xiaoyu Huang, Takara E. Truong, Carmelo Sferrazza, Yi Ma, Rocky Duan, Pieter Abbeel, Guanya Shi, Karen Liu, Angjoo Kanazawa Also at Poster Session II · 5:00–6:30 PM · Poster 63 · JW Marriott Paper ↗ 10:30–11:00 AMCST Oral · O5 Dexterous learning, grasping and assembly Hilton Austin EgoScale: Scaling Dexterous Manipulation with Diverse Egocentric Human Data Ruijie Zheng, Dantong Niu, Yuqi Xie, Jing Wang, Mengda Xu, Yunfan Jiang, Fernando Castañeda, Fengyuan Hu, You Liang Tan, Letian Fu, Trevor Darrell, Furong Huang, Yuke Zhu, Danfei Xu, Linxi Fan Also at Poster Session II · 5:00–6:30 PM · Poster 54 · JW Marriott Paper ↗ 11:30 AM–12:00 PMCST Oral · O7 Humanoid data, control and skills Hilton Austin Session chair: Koushil Sreenath SuperMimic: Scaling Humanoid Whole-Body Control with One Differentiable World Model Qiayuan Liao, Yiyang Shao, Junfeng Long, Kevin Zakka, Roberto Horowitz, Pieter Abbeel, Koushil Sreenath Also at Poster Session II · 5:00–6:30 PM · Poster 217 · JW Marriott Paper ↗ 12:00–1:30 PMCST · LUNCH BREAK Late-breaking results · Posters Real2Sim2Real Griffin · Level 2 · JW Marriott Austin Griffin board 122 · LBR #26 RoboSimStudio: An Interactive Toolkit for Rapid Real2Sim of Robot Manipulation Tasks Kaiyuan Chen, Shuangyu Xie, Uksang Yoo, Xinyue Zhu, Cael Magner, Alvin Zhu, Daehwa Kim, Eric Heiden, Erwin Coumans, Miles Macklin, Spencer Huang, Ken Goldberg Late-breaking results program ↗ 5:00–6:30 PMCST Posters Poster Session II JW Marriott Poster 7 DiscreteRTC: Discrete Diffusion Policies are Natural Asynchronous Executors Pengcheng Wang, Kaiwen Hong, Chensheng Peng, Katherine Rose Driggs-Campbell, Masayoshi Tomizuka, Chenfeng Xu, Chen Tang Paper ↗ Poster 39 Improving Robotic Generalist Policies via Flow Reversal Steering Andy Tang, William Chen, Andrew Wagenmaker, Chelsea Finn, Sergey Levine Paper ↗ Poster 54 EgoScale: Scaling Dexterous Manipulation with Diverse Egocentric Human Data Ruijie Zheng, Dantong Niu, Yuqi Xie, Jing Wang, Mengda Xu, Yunfan Jiang, Fernando Castañeda, Fengyuan Hu, You Liang Tan, Letian Fu, Trevor Darrell, Furong Huang, Yuke Zhu, Danfei Xu, Linxi Fan Authors listed under Tuesday, Oral O5 Paper ↗ Poster 63 Flow Policy Gradients for Robot Control Brent Yi, Hongsuk Choi, Himanshu Gaurav Singh, Xiaoyu Huang, Takara E. Truong, Carmelo Sferrazza, Yi Ma, Rocky Duan, Pieter Abbeel, Guanya Shi, Karen Liu, Angjoo Kanazawa Authors listed under Tuesday, Oral O4 Paper ↗ Poster 77 Why Does Action Chunking Improve Behavioral Cloning Performance in Robotic Control? Filippo Lazzati, Kyle Stachowicz, William Chen, Alberto Maria Metelli, Andrew Wagenmaker, Sergey Levine Paper ↗ Poster 142 FTP-1: A Generalist Foundation Tactile Policy Across Tactile Sensors for Contact-Rich Manipulation Chengbo Yuan, Zicheng Zhang, Mingjie Zhou, Wendi Chen, Yi Wang, Zhuoyang Liu, Dantong Niu, Shuo Wang, Hui Zhang, Wenkang Zhang, Yingdong Hu, Yuanqing Gong, Wanli Xing, Chuan Wen, Cewu Lu, Kaifeng Zhang, Yang Gao Paper ↗ Poster 153 PTLD: Sim-to-Real Privileged Tactile Latent Distillation for Dexterous Manipulation Rosy Chen, Mustafa Mukadam, Michael Kaess, Tingfan Wu, Francois Robert Hogan, Jitendra Malik, Akash Sharma Paper ↗ Poster 184 Counterfactual Video Generation Enables Scalable Humanoid Loco-Manipulation Zihan Wang, Zhen Wu, Pieter Abbeel, Rocky Duan, Jitendra Malik, Carmelo Sferrazza, Karen Liu, Guanya Shi, Angjoo Kanazawa Paper ↗ Poster 189 VLK: Learning Humanoid Loco-Manipulation from Synthetic Interactions in Reconstructed Scenes Yen-Jen Wang, Jiaman Li, Sirui Chen, Takara E. Truong, Pei Xu, Pieter Abbeel, Rocky Duan, Koushil Sreenath, Angjoo Kanazawa, Carmelo Sferrazza, Guanya Shi, Karen Liu Paper ↗ Poster 195 Social Humanoid: Socially Responsive Human–Humanoid Interaction Vongani Hlavutelo Maluleke, James Ni, Kie Horiuchi, Lea Wilken, Jiahui Lei, Evonne Ng, Roei Herzig, Jitendra Malik, Trevor Darrell, Angjoo Kanazawa Poster 217 SuperMimic: Scaling Humanoid Whole-Body Control with One Differentiable World Model Qiayuan Liao, Yiyang Shao, Junfeng Long, Kevin Zakka, Roberto Horowitz, Pieter Abbeel, Koushil Sreenath Authors listed under Tuesday, Oral O7 Paper ↗ Wednesday, November 11 Main conference12 papers 8:30–9:00 AMCST Spotlight · S6 Optimization, agentic planning and evaluation Hilton Austin Session chair: Negar Mehr Playful Agentic Robot Learning Junyi Zhang, Jiaxin Ge, Hanjun Yoo, Letian Fu, Zihan Yang, Yaowei Liu, Raj Saravanan, Shaofeng Yin, Justin Yu, Dantong Niu, Zirui Wang, Roei Herzig, Ken Goldberg, Yutong Bai, David M. Chan, Ion Stoica, Angjoo Kanazawa, Jiahui Lei, Haiwen Feng, Trevor Darrell Also at Poster Session III · 10:30 AM–12:00 PM · Poster 99 · JW Marriott Paper ↗ GaP: A Graph-as-Policy Multi-Agent Self-Learning Harness For Variational Automation Tasks Kaiyuan Chen, Shuangyu Xie, Letian Fu, Justin Yu, William Pacini, Sandeep Bajamahal, Hudson Kim, Jaimyn Drake, Daehwa Kim, Haoru Xue, Jonathan Francis, Christian Juette, Peter Schaldenbrand, Muhammet Yunus Seker, Ruwan Wickramarachchi, Uksang Yoo, Guanzhi Wang, Adithyavairavan Murali, Balakumar Sundaralingam, S. Shankar Sastry, Yuke Zhu, Linxi Fan, Spencer Huang, Ken Goldberg Also at Poster Session III · 10:30 AM–12:00 PM · Poster 100 · JW Marriott Paper ↗ 9:00–9:30 AMCST Spotlight · S7 Humanoid locomotion and whole-body control Hilton Austin LadderMan: Learning Humanoid Perceptive Ladder Climbing Siheng Zhao, Yuanhang Zhang, Ziqi Lu, Pieter Abbeel, Rocky Duan, Koushil Sreenath, Yue Wang, Karen Liu, Guanya Shi Also at Poster Session III · 10:30 AM–12:00 PM · Poster 195 · JW Marriott Paper ↗ ResSafe: Learning Safety Filtering with Residual Reinforcement Learning for Humanoids Gechen Qu, Tong Zhang, Bike Zhang, Yen-Jen Wang, Koushil Sreenath, Claire Tomlin, Jason Jangho Choi Also at Poster Session III · 10:30 AM–12:00 PM · Poster 198 · JW Marriott Paper ↗ TANGO: Humanoid Navigation in Cluttered Environments with a Whole-Body Vision-Language-Action Model Anqi Li, Yuxin Chen, Zhaobo Li, Zhuo Cao, Junli Ren, Masayoshi Tomizuka, Dhruv Shah Also at Poster Session III · 10:30 AM–12:00 PM · Poster 200 · JW Marriott Paper ↗ 10:30 AM–12:00 PMCST Posters Poster Session III JW Marriott Poster 51 Do as I Do: Dexterous Manipulation Data from Everyday Human Videos Bhawna Paliwal, Haritheja Etukuru, William Liang, Pieter Abbeel, Nur Muhammad Mahi Shafiullah, Jitendra Malik Paper ↗ Poster 68 WARP-RM: A Warp-Augmented Relative Progress Reward Model for Data Curation Justin Yu, Andrew Goldberg, Kavish Kondap, Karim El-Refai, Ethan Ransing, Qianzhong Chen, Mac Schwager, Fred Shentu, Philipp Wu, Ken Goldberg Paper ↗ Poster 99 Playful Agentic Robot Learning Junyi Zhang, Jiaxin Ge, Hanjun Yoo, Letian Fu, Zihan Yang, Yaowei Liu, Raj Saravanan, Shaofeng Yin, Justin Yu, Dantong Niu, Zirui Wang, Roei Herzig, Ken Goldberg, Yutong Bai, David M. Chan, Ion Stoica, Angjoo Kanazawa, Jiahui Lei, Haiwen Feng, Trevor Darrell Authors listed under Wednesday, Spotlight S6 Paper ↗ Poster 100 GaP: A Graph-as-Policy Multi-Agent Self-Learning Harness For Variational Automation Tasks Kaiyuan Chen, Shuangyu Xie, Letian Fu, Justin Yu, William Pacini, Sandeep Bajamahal, Hudson Kim, Jaimyn Drake, Daehwa Kim, Haoru Xue, Jonathan Francis, Christian Juette, Peter Schaldenbrand, Muhammet Yunus Seker, Ruwan Wickramarachchi, Uksang Yoo, Guanzhi Wang, Adithyavairavan Murali, Balakumar Sundaralingam, S. Shankar Sastry, Yuke Zhu, Linxi Fan, Spencer Huang, Ken Goldberg Authors listed under Wednesday, Spotlight S6 Paper ↗ Poster 135 T-Rex: Tactile-Reactive Dexterous Manipulation Dantong Niu, Zhuoyang Liu, Zekai Wang, Boning Shao, Zhao-Heng Yin, Anirudh Pai, Yuvan Sharma, Stefano Saravalle, Ruijie Zheng, Jing Wang, Ryan Punamiya, Mengda Xu, Yuqi Xie, Yunfan Jiang, Letian Fu, Konstantinos Kallidromitis, Matteo Gioia, Junyi Zhang, Jiaxin Ge, Haiwen Feng, Fabio Galasso, Wei Zhan, David M. Chan, Yutong Bai, Roei Herzig, Jiahui Lei, Fei-Fei Li, Ken Goldberg, Jitendra Malik, Pieter Abbeel, Yuke Zhu, Danfei Xu, Linxi Fan, Trevor Darrell Paper ↗ Poster 148 Tactile Curiosity Drives Robot Interaction Klemens Iten, Alexander Proshkin, Bhavya Sukhija, Stelian Coros, Andreas Krause, Pieter Abbeel, Carmelo Sferrazza Paper ↗ Poster 159 RPL: Learning Robust Humanoid Perceptive Locomotion on Challenging Terrains Yuanhang Zhang, Younggyo Seo, Juyue Chen, Yifu Yuan, Koushil Sreenath, Pieter Abbeel, Carmelo Sferrazza, Karen Liu, Rocky Duan, Guanya Shi Paper ↗ Poster 175 TEXEDO: Test Time Scaling for Controller-aware Language-conditioned Humanoid Motion Generation Jianuo Cao, Yuxin Chen, Yuzhen Song, Masayoshi Tomizuka, Chenran Li, Thomas Tian Paper ↗ Poster 178 CLIFT: Turning Gemini Robotics On-Device into Humanoid Specialists via Non-Invasive Closed-Loop Iterative Fine-Tuning Yuxin Chen, Hari Srikanth, Nathan Jew, Menglin Wu, Pengcheng Wang, Junli Ren, Masayoshi Tomizuka, Peng Xu, Jinyu Xie, Thomas Tian Paper ↗ Poster 195 LadderMan: Learning Humanoid Perceptive Ladder Climbing Siheng Zhao, Yuanhang Zhang, Ziqi Lu, Pieter Abbeel, Rocky Duan, Koushil Sreenath, Yue Wang, Karen Liu, Guanya Shi Authors listed under Wednesday, Spotlight S7 Paper ↗ Poster 198 ResSafe: Learning Safety Filtering with Residual Reinforcement Learning for Humanoids Gechen Qu, Tong Zhang, Bike Zhang, Yen-Jen Wang, Koushil Sreenath, Claire Tomlin, Jason Jangho Choi Authors listed under Wednesday, Spotlight S7 Paper ↗ Poster 200 TANGO: Humanoid Navigation in Cluttered Environments with a Whole-Body Vision-Language-Action Model Anqi Li, Yuxin Chen, Zhaobo Li, Zhuo Cao, Junli Ren, Masayoshi Tomizuka, Dhruv Shah Authors listed under Wednesday, Spotlight S7 Paper ↗ Thursday, November 12 WorkshopsTalks, papers and organizing roles 8:40–9:50 AMCST Workshop Roadmap to Sample-Efficient Real-World Reinforcement Learning (R2RL) · Keynote block JW Marriott · Room 213 Zhiyuan “Paul” Zhou Sergey Levine’s lab. Speaks during the keynote block. Session details ↗ 9:40–10:15 AMCST Workshop Bimanual Dexterous Tool Use · Spotlights JW Marriott · Rooms 303–304 T-Rex: Tactile-Reactive Dexterous Manipulation Dantong Niu, Zhuoyang Liu, Zekai Wang, Boning Shao, Zhao-Heng Yin, Anirudh Pai, Yuvan Sharma, Stefano Saravalle, Ruijie Zheng, Jing Wang, Ryan Punamiya, Mengda Xu, Yuqi Xie, Yunfan Jiang, Letian Fu, Konstantinos Kallidromitis, Matteo Gioia, Junyi Zhang, Jiaxin Ge, Haiwen Feng, Fabio Galasso, Wei Zhan, David M. Chan, Yutong Bai, Roei Herzig, Jiahui Lei, Fei-Fei Li, Ken Goldberg, Jitendra Malik, Pieter Abbeel, Yuke Zhu, Danfei Xu, Linxi Fan, Trevor Darrell Authors listed under Wednesday, Poster Session III Paper ↗ Do as I Do: Dexterous Manipulation Data from Everyday Human Videos Bhawna Paliwal, Haritheja Etukuru, William Liang, Pieter Abbeel, Nur Muhammad Mahi Shafiullah, Jitendra Malik Authors listed under Wednesday, Poster Session III Paper ↗ Workshop program ↗ 10:15–10:40 AMCST Workshop Bimanual Dexterous Tool Use · Posters & demos JW Marriott · Rooms 303–304 T-Rex: Tactile-Reactive Dexterous Manipulation Dantong Niu, Zhuoyang Liu, Zekai Wang, Boning Shao, Zhao-Heng Yin, Anirudh Pai, Yuvan Sharma, Stefano Saravalle, Ruijie Zheng, Jing Wang, Ryan Punamiya, Mengda Xu, Yuqi Xie, Yunfan Jiang, Letian Fu, Konstantinos Kallidromitis, Matteo Gioia, Junyi Zhang, Jiaxin Ge, Haiwen Feng, Fabio Galasso, Wei Zhan, David M. Chan, Yutong Bai, Roei Herzig, Jiahui Lei, Fei-Fei Li, Ken Goldberg, Jitendra Malik, Pieter Abbeel, Yuke Zhu, Danfei Xu, Linxi Fan, Trevor Darrell Authors listed under Wednesday, Poster Session III Paper ↗ Do as I Do: Dexterous Manipulation Data from Everyday Human Videos Bhawna Paliwal, Haritheja Etukuru, William Liang, Pieter Abbeel, Nur Muhammad Mahi Shafiullah, Jitendra Malik Authors listed under Wednesday, Poster Session III Paper ↗ Workshop program ↗ 10:35–11:05 AMCST Workshop Everything Beneath the Policy · Posters Hilton Austin · Salon E, 4th floor TouchScale: 500 Hours of Human Vision and Touch for Visual-Tactile Learning Dayou Li, Hao Wang, Qianqian Yang, Zihao Zhu, Haoquan Fang, Ziyao Zeng, Yan Han, Zihan Wang, Yan Wang, Baoru Huang, Dilin Wang, Kenji Shimada, Yiyue Luo, Manling Li, Teresa Lv, Mustafa Mukadam, Rakesh Ranjan, Ruohan Zhang, Qi He, Changliu Liu, Xu Chen, Marco Pavone, Bangya Liu, Jiachen Li, Masayoshi Tomizuka, Zhiwen Fan Workhorse: Learning Robust Whole-Body Humanoid Loco-Manipulation from Human Data Songbo Hu, Qiayuan Liao, Yufeng Chi, Kevin Zakka, Sophia Shao, Pieter Abbeel, Koushil Sreenath Paper ↗ Workshop program ↗ 10:40–11:10 AMCST Workshop Bimanual Dexterous Tool Use · Invited talk JW Marriott · Rooms 303–304 Professor Jitendra Malik Talk title has not been announced. Session details ↗ 11:50 AM–12:20 PMCST Workshop R2RL · Panel discussion JW Marriott · Room 213 Zhiyuan “Paul” Zhou Panel with workshop speakers and audience volunteers. Session details ↗ 2:45–3:05 PMCST Workshop Agentic Robotics · Invited talk Room to be announced Professor Ken Goldberg Talk title has not been announced. Session details ↗ Approx. 2:55–3:25 PMCST Workshop Sim-to-Real-to-Field · Invited talks Hilton Austin · Salon E, 4th floor Professor Claire Tomlin Shared invited-talk block with Michael Lutter (Boston Dynamics). Session details ↗ 4:15–5:55 PMCST Workshop Agentic Robotics · Live demos & posters Room to be announced ASPIRE: Agentic /Skills Discovery for Robotics Runyu Lu, Yubo Wu, Ethan Kou, Haotian Lin, Letian Fu, Wenli Xiao, Ajay Mandlekar, Yinzhen Xu, Guanya Shi, Ken Goldberg, Ang Chen, Mosharaf Chowdhury, Jan Kautz, Yuke Zhu, Linxi Fan, Guanzhi Wang Agentic World Action Models Zhuoyang Liu, Dantong Niu, Botong Zhang, Boning Shao, Jing Wang, Ruijie Zheng, Yuvan Sharma, Runyu Lu, Jiaming Liu, Renrui Zhang, Roei Herzig, Yutong Bai, Ken Goldberg, Danfei Xu, Yuke Zhu, Guanzhi Wang, Linxi Fan, Trevor Darrell Reconstruct, Practice, Go Real: Guided Self-Improvement for Embodied Agents Yen-Jen Wang, Haozhe Jiang, Shuying Deng, Haoru Xue, Weirui Ye, Rocky Duan, Nika Haghtalab, S. Shankar Sastry, Pieter Abbeel, Haozhi Qi Authors listed under Monday, Late-breaking results, Agentic Robotics Workshop program ↗ Additional involvement Workshop organizers BAIR behind the program Workshop organizing roles. Do Robots Need World Models? Lasse Peters, Negar Mehr’s lab — organizer. Sim-to-Real-to-Field S. Shankar Sastry, Bike Zhang, Siming He, Jonas Frey — organizers. “Oops, I Erred” Sergey Levine — faculty advisor. Zhiyuan “Paul” Zhou and Renhao Wang — organizers. Dexterous Manipulation: Full-Stack Robotics on Learning and Design Jitendra Malik — organizer. Workshop: 2:00–6:00 PM. About this schedule Schedule compiled from the conference program, paper and project pages, and workshop programs. Workshop schedules may change; consult each linked program for updates. Coverage includes 33 main-conference papers, 4 late-breaking results posters and the workshop contributions listed above. The main conference demo track is not covered. Main-conference poster numbers follow an unofficial paper index; check the official program on the day. Hilton stage content will also be streamed to viewing rooms at the Marriott. Paper affiliations reviewed November 6, 2026; late-breaking results updated November 8, 2026. Official CoRL program ↗BAIR faculty ↗Unofficial paper & poster index ↗Back to top ↑ 0; status.textContent = (!search.value && !type.value) ? "Showing all sessions" : visible + " matching session" + (visible === 1 ? "" : "s"); } function reset() { search.value = ""; type.value = ""; filter(); } search.addEventListener("input", filter); type.addEventListener("change", filter); document.getElementById("corl-reset").addEventListener("click", function () { reset(); search.focus(); }); Array.prototype.forEach.call(root.querySelectorAll(".corl-nav a, .corl-see a"), function (a) { a.addEventListener("click", reset); }); window.addEventListener("beforeprint", reset); })();

2 days ago • 1 votes
📚 BoredReading

You seem to be enjoying this.

Join free to unlock everything.

Create free account

Already have an account? Sign in