When we were sketching how pouch users should organize their drops, the obvious first answer was folders. Everyone knows folders. Every file system has them. You'd put your "work" stuff over here, your "recipes" over there, drag things between. Done.
We said no. Not because folders are bad — they're fine for what they do — but because they'd push pouch into the wrong category. What replaced them is a concept we call streams. This post explains the difference and why it matters.
What folders actually do
A folder, stripped to its essentials, is exclusive containment with optional hierarchy. An item lives in one folder (or one folder at a time); folders can nest; navigation means descending a tree. That's it. Folders say nothing about the items inside — no retention policy, no routing, no lifespan. A "taxes" folder is identical to a "memes" folder in every systemic way; they differ only in the text of their name.
For a file system, that's the right abstraction. Files don't have different lifetimes or rules by virtue of where they live. For a relay optimized around lifecycle, it's the wrong abstraction.
What we actually wanted to express
Think about the drops a user cares about:
- A short-lived clipboard paste that should evaporate in a day
- A meeting note they want to keep indefinitely
- A family photo that they want replicated to their SAN
- A tax record that should be encrypted client-side
- An incoming drop from a collaborator that should auto-forward to Slack
Each has different policy. TTL. Retention. Replication. Encryption. Routing. The policy is intrinsic to the kind of drop it is, not a property of a folder name. And critically: a user should be able to say "this drop is that kind" in one gesture, and have the policy attach automatically.
Folders can't carry policy. You could add per-folder settings ("this folder expires after 30 days") but then the folder is doing double duty — organization plus policy — and it'll fall over when the two diverge.
The alternative: streams
A stream is a named lane with a policy bundle. Every drop lives in exactly one stream; the stream dictates its behavior. For v0 of pouch we shipped two:
-
inbox— ephemeral default. Drops here carry a short TTL by default; they clean themselves up. -
kept— durable. No TTL. You moved it here because it's worth keeping.
Future streams we've designed (not yet built):
-
archive— durable + replicated. Policy: keep at least two copies across user-configured targets (server + local SAN, or server + cloud backup). -
vault— durable + client-side encrypted. Server stores ciphertext only. -
transit— short TTL + automatic forwarding to an external sink (Slack, email, webhook), then discard.
Notice what's happening. "Stream" is the unit where policy lives; tags remain for content-description; source remains for provenance. Three orthogonal dimensions, not one overloaded one.
Streams vs. folders side by side
| Folders | Streams | |
|---|---|---|
| Purpose | Organization by user-chosen name | Policy lane (TTL, retention, replication) |
| Exclusive | Yes (one folder per item) | Yes (one stream per drop) |
| Hierarchical | Yes — drifts to tree | No — flat by design |
| Carries behavior | No (name is text) | Yes (policy bundle) |
| Orthogonal to tags | No — tends to compete with tagging | Yes — streams describe how, tags describe what |
Why this decision was hard
"No folders" fights user expectations. Everyone asks where to put something; the honest answer is "you don't put it anywhere, you tag and stream it." That takes explanation, and the concept has to be visible in the UI or users silently bail.
We went back and forth. The alternative we considered most seriously was "just ship folders, add stream-like policies later." We rejected it because once folders exist, users build muscle memory around them, and retrofitting policy onto a folder system creates the overload we started by avoiding. Better to ship the right abstraction first and invest in making it legible.
The test: does it compose?
A good abstraction composes cleanly with the rest of the system. Streams hit that bar:
- Every subscription-state rule, TTL sweep, and replication policy dispatches on stream name — one table, one lookup.
-
New streams are config, not schema changes. When we add
archive, it's a new row in a streams table with its own policy; no code for "what happens to the 'inbox' flag" has to change. -
The "move to" primitive is universal. The UI has one action
(
⋮ → Move to...) that lists available streams. No per-folder menus, no drag-and-drop hierarchy.
Folders would have had all of these features reimplemented as per-folder overrides, effectively rebuilding stream semantics inside a folder UI. At that point, call it what it is.
What this doesn't solve
Streams give us lanes. They don't give us intent within a
lane. A drop can be in the kept stream and
still be a meeting note, a recipe, or a tax form — and users
will want to find "all recipes" regardless of stream.
That's what tags are for. And when tags aren't enough, it's what the future enrichment layer is for — LLM-driven auto-classification, entity extraction, summarization. Each of those dimensions stays orthogonal to streams. Streams dictate how the drop is treated over time; tags and enrichment dictate what it's about.
The one-line summary
Folders describe where. Streams describe how. Pouch needed the second, so we shipped it instead of the first.
Next post: Picking IBM Plex — one type system for app and content.