Arc to zen migration
Use when migrating Arc browser spaces/workspaces into Zen Browser, or bulk-creating Zen workspaces, folders, essentials, or pinned tabs by editing the session store. Covers reading/writing Zen's mozlz4 session file and its folder/group/space schema.From its SKILL.md
npx -y skills add shub-rajput/arc-to-zen-migrationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
- runs commandsInstructs the agent to run 6 commands, including `python3 scripts/migrate.py --list` and 5 more.
SKILL.md
5.7 KB, ~1.4k tokens by cl100k_base, as published. Nobody here has run it
Arc → Zen Migration
Overview
Zen has no Arc importer. But Zen (Firefox-based) keeps its whole tab/folder/workspace state in one compressed file you can script against, so Arc spaces can be rebuilt in bulk — folders become folders, not flat pins.
Read side (Arc): ~/Library/Application Support/Arc/StorableSidebar.json — plain JSON holding every space, folder, and pinned tab. No manual pasting needed.
Write side (Zen): <profile>/zen-sessions.jsonlz4 — Mozilla-lz4 (mozLz40\0) compressed JSON.
Tools:
scripts/arc_extract.py— reads Arc's sidebar, returns each space as a nested tree.scripts/zen_session.py— read/write Zen's mozlz4 session + folder/tab/essential builders.scripts/migrate.py— end-to-end: Arc space → Zen workspace (preserves nested folders).scripts/migrate_example.py— manual fill-in template (when there's no Arc file, e.g. user pastes URLs).
When to Use
- "Migrate my Arc workspaces/spaces to Zen"
- "Bulk add folders / pinned tabs / essentials to Zen"
- Recreating Arc's folder structure inside a Zen workspace
Not for: bookmarks (use Arc export HTML → Zen bookmark import) or passwords (use a password manager / keychain export).
The Iron Rule
Zen MUST be fully quit (Cmd+Q) before writing. It rewrites the session on exit and will clobber your changes otherwise. Always backup() first — a wrong schema corrupts the session; the .bak restores instantly.
Workflow (automatic — Arc installed)
- Quit Zen (Cmd+Q) — non-negotiable (see Iron Rule).
- Preview:
python3 scripts/migrate.py --listprints Arc spaces ↔ Zen workspaces. - Migrate everything from zero:
python3 scripts/migrate.py --all --favorites— creates a Zen workspace per Arc space (with Arc's emoji icon), imports folders + pins, and adds Arc's global Favorites as global essentials. - Or one space:
python3 scripts/migrate.py "Home" --favorites(creates the workspace if missing;--zen "Name"maps to a differently-named one;--essentials Npromotes the first N top-level pins to essentials). - Reopen Zen, verify. Re-runnable —
clear_workspacewipes the target first. Restore the.bakif wrong.
Mapping Arc → Zen: space list → folder (nesting preserved) · space top-level tab → regular pin · global Favorites (topApps) → global essentials.
Workflow (manual — no Arc file, user pastes URLs)
Use migrate_example.py: fill ESSENTIALS/PINS/FOLDERS, quit Zen, run. Screenshots of the Arc sidebar are enough to fill it.
If Zen's schema drifted (script misbehaves): make ONE folder with 2 tabs by hand in Zen, quit, zen_session.py <profile> --dump, compare the live folders[]/groups[]/tabs[] shapes, update the builders.
Schema (Zen 1.20.x / Firefox 151)
A folder = two synced records sharing one id, plus member tabs:
| Where | Key fields |
|---|---|
folders[] | id, name, workspaceId, collapsed, parentId:null, emptyTabIds:[], userIcon |
groups[] | id (same), name, color:"zen-workspace-color", collapsed |
tabs[] (member) | groupId:<folder id>, zenWorkspace:<space uuid>, pinned:true, zenEssential:false |
- Essential:
zenEssential:true. Scoped by CONTAINER (userContextId), notzenWorkspace— this is the #1 gotcha. Withzen.workspaces.separate-essentials=true(Zen default), an essential shows only in workspaces whosecontainerTabIdmatches itsuserContextId;userContextId:0= the default container = the first/Home workspace. To make essentials global (Arc-style, same in every space), setzen.workspaces.separate-essentials=false(viauser.js) and useuserContextId:0/zenWorkspace:null. For a per-workspace essential, setuserContextIdto that workspace'scontainerTabId. - Plain pin:
zenEssential:false,zenWorkspace:<uuid>, nogroupId. Scoped byzenWorkspace(works withuserContextId:0). - Workspace lives in
spaces[]:{uuid, name, icon(emoji), containerTabId, position, theme}.ensure_workspace()creates one if absent. - Ordering = tab array order.
tab.indexis the active history-entry pointer (set to 1), NOT position. - IDs are
<epoch_ms>-<counter>. Tabs need only a minimalentries:[{url,title,triggeringPrincipal_base64:"{\"3\":{}}"}]; Firefox fills the rest on load. - Skip
arc://*URLs — they don't resolve in Zen.
Library Quickref
from zen_session import ZenSession, find_profiles
s = ZenSession(find_profiles()[0])
s.backup()
home = s.workspace_by_name("Home")
s.clear_folders(workspace=home) # idempotent re-runs
s.add_essential("https://discord.com/") # global top icon
s.add_tab("https://news.com/", workspace=home) # plain pin
fid = s.add_folder("Finance", home)
s.add_tab("https://sheet/", workspace=home, folder_id=fid)
s.save() # Zen must be quit
Common Mistakes
- Writing while Zen runs → changes vanish on quit. Quit first.
- Folder in only one array → ghost/empty folder. Always write BOTH
folders[]andgroups[](the library does). - Tab missing
zenWorkspace→ tab lands in the wrong/no space. Set it (essentials usenull). - liblz4 not found →
brew install lz4(mac) /apt install liblz4-1(linux); fix the path list inzen_session.pyif needed. - No backup → re-run with
backup(); keep the.bakuntil verified.
What ships with it: 7 files
28.6 KB alongside SKILL.md, 4 of them executable
scripts/
- arc_extract.pyruns5.1 KB
- migrate_example.pyruns1.8 KB
- migrate.pyruns4.8 KB
- zen_session.pyruns10.6 KB
- .gitignore229 B
- LICENSE1.0 KB
- README.md5.0 KB