Arc to zen migration
A Claude Code skill that migrates Arc browser spaces into Zen Browser, automatically, from the files. Folders, pins, and favorites carried over with nesting preserved.
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.
One thing 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.
What its author says it does
Copied from the file, not written here
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.
SKILL.md
5.7 KB, 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.