7 Real-World Walkthrough: Weather Analysis Pipeline
Last modified: 2026-02-08
Overview
This walkthrough demonstrates a realistic data pipeline with multiple stages and branching dependencies. Weβll simulate a weather analysis workflow where raw sensor readings are cleaned, then fed into two independent analyses β one for temperature trends and one for rainfall totals. Both analyses share the same cleaned data, so Pocket caches it once and reuses it.
This builds on the concepts from Recursive Caching in Pipelines, adding branching dependencies where two analyses share a common upstream computation.
The dependency graph: fetch-readings β clean-data β both temperature-trends and rainfall-totals β summary.
Setup
(ns pocket-book.real-world-walkthrough
(:require
;; Logging setup for this chapter (see Logging chapter):
[pocket-book.logging]
;; Pocket API:
[scicloj.pocket :as pocket]
;; Annotating kinds of visualizations:
[scicloj.kindly.v4.kind :as kind]
;; Filesystem utilities:
[babashka.fs :as fs]))(def cache-dir "/tmp/pocket-walkthrough")(pocket/set-base-cache-dir! cache-dir)10:06:34.664 INFO scicloj.pocket - Cache dir set to: /tmp/pocket-walkthrough
"/tmp/pocket-walkthrough"(pocket/cleanup!)10:06:34.665 INFO scicloj.pocket - Cache cleanup: /tmp/pocket-walkthrough
{:dir "/tmp/pocket-walkthrough", :existed false}Pipeline functions
Each function simulates real work with a short delay. Note that these are plain Clojure functions β they know nothing about caching.
(defn fetch-readings
"Simulate fetching raw sensor data for a city."
[opts]
(println " Fetching readings for" (:city opts) "...")
(Thread/sleep 300)
{:city (:city opts)
:source (:source opts)
:readings (case (:city opts)
"Paris"
[{:day 1 :temp-c 15.0 :rain-mm 2.1}
{:day 2 :temp-c 17.3 :rain-mm 0.0}
{:day 3 :temp-c 14.6 :rain-mm 7.8}
{:day 4 :temp-c 18.1 :rain-mm 0.0}
{:day 5 :temp-c 13.9 :rain-mm 4.5}
{:day 6 :temp-c 16.7 :rain-mm 0.0}
{:day 7 :temp-c 19.2 :rain-mm 1.0}]
;; default (London, etc.)
[{:day 1 :temp-c 18.2 :rain-mm 0.0}
{:day 2 :temp-c 21.5 :rain-mm 5.2}
{:day 3 :temp-c 19.8 :rain-mm 12.1}
{:day 4 :temp-c 22.0 :rain-mm 0.0}
{:day 5 :temp-c 16.3 :rain-mm 8.4}
{:day 6 :temp-c 20.1 :rain-mm 0.0}
{:day 7 :temp-c 23.7 :rain-mm 3.3}])})(defn clean-data
"Remove readings with missing values and round numbers."
[raw-data opts]
(println " Cleaning data for" (:city raw-data) "with" opts "...")
(Thread/sleep 200)
(let [precision (:precision opts 10)]
(update raw-data :readings
(fn [rs]
(->> rs
(filter #(and (:temp-c %) (:rain-mm %)))
(mapv #(-> %
(update :temp-c (fn [t] (Math/round (* t (double precision)))))
(update :rain-mm (fn [r] (Math/round (* r (double precision))))))))))))(defn temperature-trends
"Compute temperature statistics from cleaned data."
[clean-data opts]
(println " Analyzing temperature for" (:city clean-data) "...")
(Thread/sleep 300)
(let [temps (map :temp-c (:readings clean-data))
n (count temps)]
{:city (:city clean-data)
:unit (:unit opts)
:min-temp (apply min temps)
:max-temp (apply max temps)
:mean-temp (quot (reduce + temps) n)
:days n}))(defn rainfall-totals
"Compute rainfall statistics from cleaned data."
[clean-data opts]
(println " Analyzing rainfall for" (:city clean-data) "...")
(Thread/sleep 300)
(let [rains (map :rain-mm (:readings clean-data))
rainy-days (count (filter pos? rains))]
{:city (:city clean-data)
:unit (:unit opts)
:total-rain (reduce + rains)
:rainy-days rainy-days
:dry-days (- (count rains) rainy-days)}))(defn summary
"Combine temperature and rainfall analyses into a report."
[temp-analysis rain-analysis]
(println " Generating summary for" (:city temp-analysis) "...")
(Thread/sleep 200)
(merge temp-analysis rain-analysis
{:report (str (:city temp-analysis)
": temp range "
(:min-temp temp-analysis) "β"
(:max-temp temp-analysis)
", total rain "
(:total-rain rain-analysis)
" over " (:rainy-days rain-analysis) " days")}))First run: everything computes
We build the pipeline using cached. Each call returns a Cached object that we pass directly to the next stage. Pocket derives cache keys from the computation graph, not from intermediate values.
(println "=== First run ===")=== First run ===
nil(let [raw (pocket/cached #'fetch-readings {:city "London" :days 7 :source :api})
clean (pocket/cached #'clean-data raw {:precision 10 :remove-nulls true})
temps (pocket/cached #'temperature-trends clean {:unit :celsius})
rain (pocket/cached #'rainfall-totals clean {:unit :mm})
report (pocket/cached #'summary temps rain)]
(time (deref report)))10:06:34.678 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/summary
10:06:34.678 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/temperature-trends
10:06:34.678 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/clean-data
10:06:34.678 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/fetch-readings
Fetching readings for London ...
10:06:34.981 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/29/(pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api})
Cleaning data for London with {:precision 10, :remove-nulls true} ...
10:06:35.184 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/2c/(pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api}) {:precision 10, :remove-nulls true})
Analyzing temperature for London ...
10:06:35.486 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/17/17db4a12cb5e1ba8da076b6148be68b333bc6a16
10:06:35.486 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/rainfall-totals
Analyzing rainfall for London ...
10:06:35.788 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/a4/(pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})
Generating summary for London ...
10:06:35.990 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/50/50a0ffd14b1b8fa3a7ba7a1fa3d75cf5b26f0c57
"Elapsed time: 1312.197295 msecs"
{:report "London: temp range 163β237, total rain 290 over 4 days",
:max-temp 237,
:dry-days 3,
:unit :mm,
:city "London",
:days 7,
:total-rain 290,
:rainy-days 4,
:mean-temp 202,
:min-temp 163}Every function ran. Notice the log messages showing cache misses, computations, and writes.
Second run: everything from cache
Running the exact same pipeline again β nothing recomputes:
(println "\n=== Second run (fully cached) ===")
=== Second run (fully cached) ===
nil(let [raw (pocket/cached #'fetch-readings {:city "London" :days 7 :source :api})
clean (pocket/cached #'clean-data raw {:precision 10 :remove-nulls true})
temps (pocket/cached #'temperature-trends clean {:unit :celsius})
rain (pocket/cached #'rainfall-totals clean {:unit :mm})
report (pocket/cached #'summary temps rain)]
(time (deref report)))"Elapsed time: 0.227553 msecs"
{:report "London: temp range 163β237, total rain 290 over 4 days",
:max-temp 237,
:dry-days 3,
:unit :mm,
:city "London",
:days 7,
:total-rain 290,
:rainy-days 4,
:mean-temp 202,
:min-temp 163}No log output β served entirely from the in-memory cache.
Changing an upstream input
Now suppose we want a different city. The entire pipeline recomputes because the root input changed:
(println "\n=== Different city ===")
=== Different city ===
nil(let [raw (pocket/cached #'fetch-readings {:city "Paris" :days 7 :source :api})
clean (pocket/cached #'clean-data raw {:precision 10 :remove-nulls true})
temps (pocket/cached #'temperature-trends clean {:unit :celsius})
rain (pocket/cached #'rainfall-totals clean {:unit :mm})
report (pocket/cached #'summary temps rain)]
(time (deref report)))10:06:36.001 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/summary
10:06:36.001 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/temperature-trends
10:06:36.001 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/clean-data
10:06:36.001 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/fetch-readings
Fetching readings for Paris ...
10:06:36.303 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/49/(pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api})
Cleaning data for Paris with {:precision 10, :remove-nulls true} ...
10:06:36.505 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/36/(pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api}) {:precision 10, :remove-nulls true})
Analyzing temperature for Paris ...
10:06:36.807 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/4d/4d7d654476f96c5a4808c863dd3c29e845d4a9f6
10:06:36.808 INFO scicloj.pocket.impl.cache - Cache miss, computing: pocket-book.real-world-walkthrough/rainfall-totals
Analyzing rainfall for Paris ...
10:06:37.109 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/6d/(pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})
Generating summary for Paris ...
10:06:37.311 DEBUG scicloj.pocket.impl.cache - Cache write: /tmp/pocket-walkthrough/be/be026e38b57ab3e7ce5623eff753a616df974e93
"Elapsed time: 1311.025628 msecs"
{:report "Paris: temp range 139β192, total rain 154 over 4 days",
:max-temp 192,
:dry-days 3,
:unit :mm,
:city "Paris",
:days 7,
:total-rain 154,
:rainy-days 4,
:mean-temp 164,
:min-temp 139}But running it again is instant β Paris is now cached too:
(println "\n=== Paris again (cached) ===")
=== Paris again (cached) ===
nil(let [raw (pocket/cached #'fetch-readings {:city "Paris" :days 7 :source :api})
clean (pocket/cached #'clean-data raw {:precision 10 :remove-nulls true})
temps (pocket/cached #'temperature-trends clean {:unit :celsius})
rain (pocket/cached #'rainfall-totals clean {:unit :mm})
report (pocket/cached #'summary temps rain)]
(time (deref report)))"Elapsed time: 0.319826 msecs"
{:report "Paris: temp range 139β192, total rain 154 over 4 days",
:max-temp 192,
:dry-days 3,
:unit :mm,
:city "Paris",
:days 7,
:total-rain 154,
:rainy-days 4,
:mean-temp 164,
:min-temp 139}No log output β served entirely from the in-memory cache.
Inspecting the cache on disk
Letβs look at what Pocket stored. The cache directory is organized by a SHA-1 prefix, then a human-readable directory named after the function and arguments.
Cache entries
(pocket/cache-entries)[{:path
"/tmp/pocket-walkthrough/17/17db4a12cb5e1ba8da076b6148be68b333bc6a16",
:id
"(pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius})",
:fn-name "pocket-book.real-world-walkthrough/temperature-trends",
:args-str
"[(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}]",
:created-at "2026-02-09T08:06:35.485068512Z"}
{:path
"/tmp/pocket-walkthrough/be/be026e38b57ab3e7ce5623eff753a616df974e93",
:id
"(pocket-book.real-world-walkthrough/summary (pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}) (pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm}))",
:fn-name "pocket-book.real-world-walkthrough/summary",
:args-str
"[(pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}) (pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})]",
:created-at "2026-02-09T08:06:37.310197629Z"}
{:path
"/tmp/pocket-walkthrough/2c/(pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true})",
:id
"(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true})",
:fn-name "pocket-book.real-world-walkthrough/clean-data",
:args-str
"[(pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}]",
:created-at "2026-02-09T08:06:35.183392972Z"}
{:path
"/tmp/pocket-walkthrough/6d/(pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})",
:id
"(pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})",
:fn-name "pocket-book.real-world-walkthrough/rainfall-totals",
:args-str
"[(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm}]",
:created-at "2026-02-09T08:06:37.108761748Z"}
{:path
"/tmp/pocket-walkthrough/50/50a0ffd14b1b8fa3a7ba7a1fa3d75cf5b26f0c57",
:id
"(pocket-book.real-world-walkthrough/summary (pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}) (pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm}))",
:fn-name "pocket-book.real-world-walkthrough/summary",
:args-str
"[(pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}) (pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})]",
:created-at "2026-02-09T08:06:35.989495101Z"}
{:path
"/tmp/pocket-walkthrough/36/(pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true})",
:id
"(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true})",
:fn-name "pocket-book.real-world-walkthrough/clean-data",
:args-str
"[(pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}]",
:created-at "2026-02-09T08:06:36.504746234Z"}
{:path
"/tmp/pocket-walkthrough/49/(pocket-book.real-world-walkthrough_fetch-readings {:city \"Paris\", :days 7, :source :api})",
:id
"(pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api})",
:fn-name "pocket-book.real-world-walkthrough/fetch-readings",
:args-str "[{:city \"Paris\", :days 7, :source :api}]",
:created-at "2026-02-09T08:06:36.302192454Z"}
{:path
"/tmp/pocket-walkthrough/29/(pocket-book.real-world-walkthrough_fetch-readings {:city \"London\", :days 7, :source :api})",
:id
"(pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api})",
:fn-name "pocket-book.real-world-walkthrough/fetch-readings",
:args-str "[{:city \"London\", :days 7, :source :api}]",
:created-at "2026-02-09T08:06:34.980022089Z"}
{:path
"/tmp/pocket-walkthrough/a4/(pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})",
:id
"(pocket-book.real-world-walkthrough/rainfall-totals (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})",
:fn-name "pocket-book.real-world-walkthrough/rainfall-totals",
:args-str
"[(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"London\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm}]",
:created-at "2026-02-09T08:06:35.787520891Z"}
{:path
"/tmp/pocket-walkthrough/4d/4d7d654476f96c5a4808c863dd3c29e845d4a9f6",
:id
"(pocket-book.real-world-walkthrough/temperature-trends (pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius})",
:fn-name "pocket-book.real-world-walkthrough/temperature-trends",
:args-str
"[(pocket-book.real-world-walkthrough/clean-data (pocket-book.real-world-walkthrough/fetch-readings {:city \"Paris\", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :celsius}]",
:created-at "2026-02-09T08:06:36.806596162Z"}]Cache statistics
(pocket/cache-stats){:total-entries 10,
:total-size-bytes 16707,
:entries-per-fn
{"pocket-book.real-world-walkthrough/temperature-trends" 2,
"pocket-book.real-world-walkthrough/summary" 2,
"pocket-book.real-world-walkthrough/clean-data" 2,
"pocket-book.real-world-walkthrough/rainfall-totals" 2,
"pocket-book.real-world-walkthrough/fetch-readings" 2}}Directory tree
Each entry contains either a value.nippy file (serialized value) or a nil marker, plus a meta.edn with metadata. Here is the actual cache directory tree, generated dynamically.
Notice that some entries use human-readable directory names while others fall back to SHA-1 hashes β this happens when the cache key (which includes the full upstream computation chain) exceeds 240 characters. The meta.edn inside each entry always contains the full details.
(pocket/dir-tree)pocket-walkthrough
βββ 17
β βββ 17db4a12cb5e1ba8da076b6148be68b333bc6a16
β βββ meta.edn
β βββ value.nippy
βββ 29
β βββ (pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api})
β βββ meta.edn
β βββ value.nippy
βββ 2c
β βββ (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api}) {:precision 10, :remove-nulls true})
β βββ meta.edn
β βββ value.nippy
βββ 36
β βββ (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api}) {:precision 10, :remove-nulls true})
β βββ meta.edn
β βββ value.nippy
βββ 49
β βββ (pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api})
β βββ meta.edn
β βββ value.nippy
βββ 4d
β βββ 4d7d654476f96c5a4808c863dd3c29e845d4a9f6
β βββ meta.edn
β βββ value.nippy
βββ 50
β βββ 50a0ffd14b1b8fa3a7ba7a1fa3d75cf5b26f0c57
β βββ meta.edn
β βββ value.nippy
βββ 6d
β βββ (pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "Paris", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})
β βββ meta.edn
β βββ value.nippy
βββ a4
β βββ (pocket-book.real-world-walkthrough_rainfall-totals (pocket-book.real-world-walkthrough_clean-data (pocket-book.real-world-walkthrough_fetch-readings {:city "London", :days 7, :source :api}) {:precision 10, :remove-nulls true}) {:unit :mm})
β βββ meta.edn
β βββ value.nippy
βββ be
βββ be026e38b57ab3e7ce5623eff753a616df974e93
βββ meta.edn
βββ value.nippyCleanup
Remove all cached data:
(pocket/cleanup!)10:06:37.332 INFO scicloj.pocket - Cache cleanup: /tmp/pocket-walkthrough
{:dir "/tmp/pocket-walkthrough", :existed true}