| name | zellij-layout-preservation |
| description | Automatic Zellij session layout preservation with BSD immutable flag protection. Use when working with Zellij layouts, encountering "Operation not permitted" on layout files, need to save/restore session configurations, or manage protected configuration files on macOS. Covers auto-save mechanism, uchg flag protection, LaunchAgent setup, and AI agent interaction patterns. |
| allowed-tools | Read, Bash, Grep, Edit |
Zellij Layout Preservation System
Auto-save system protecting Zellij session layouts from accidental deletion by AI agents using BSD immutable flags.
Key Features:
- Auto-save every 5 minutes via LaunchAgent
- Immutable flag (
uchg) protection prevents deletion
- Session-aware updates
- Reboot-persistent configuration
Quick Reference
When to use this skill:
- Working with Zellij session layouts (tabs, panes, windows)
- Encountering "Operation not permitted" when trying to modify/delete layout files
- Need to automatically save current Zellij session configuration
- Want to protect configuration files from accidental deletion
- AI agent needs to update protected files safely
- Understanding BSD file flags on macOS
Protected File: ~/.config/zellij/layouts/default-terrylica.kdl
Session Name: default-terrylica
System Architecture
Zellij Session (active)
↓ every 5 minutes
LaunchAgent (com.terryli.zellij-save-layout.plist)
↓ triggers
Update Script (~/.local/bin/zellij-save-layout)
↓ performs
1. chflags nouchg (unlock)
2. zellij action dump-layout (save)
3. chflags uchg (lock)
↓ updates
Protected Layout File (uchg flag prevents deletion)
Components:
- Active session:
default-terrylica
- LaunchAgent: Runs every 300 seconds
- Update script: Handles lock/update/lock cycle
- Protected file:
~/.config/zellij/layouts/default-terrylica.kdl
The Immutable Flag Mechanism (uchg)
Not Oxymoronic - It's a Removable Lock
The uchg (user changeable) flag is a BSD filesystem feature that prevents file deletion/modification until removed by file owner.
Analogy: Child-safety medicine bottle
- Child tries to open → Blocked (doesn't know the push-and-twist trick)
- Adult pushes + twists → Opens (knows the trick)
In filesystem terms:
- Random script tries
rm file → Blocked (doesn't know about uchg)
- Authorized script runs
chflags nouchg → Unlocks → Updates → Locks again
How It Works
ls -lO file.kdl
rm file.kdl
chflags nouchg file.kdl
ls -lO file.kdl
rm file.kdl
Protection Hierarchy
| Who | Can Remove Flag? | Can Delete? |
|---|
| File owner | ✅ Yes | ✅ Yes (after removing flag) |
| Root/sudo | ✅ Yes | ✅ Yes (after removing flag) |
| Other users | ❌ No | ❌ No |
| AI agents | ❌ No (unless told) | ❌ No |
| Scripts | ❌ No | ❌ No |
Commands Reference
Status Checks
launchctl list | grep zellij-save-layout
ls -lhO ~/.config/zellij/layouts/default-terrylica.kdl
tail -20 /tmp/zellij-save-layout.log
ls -lh ~/.config/zellij/layouts/default-terrylica.kdl
Manual Operations
save-zellij-layout
launchctl kickstart -k gui/$(id -u)/com.terryli.zellij-save-layout
zellij action rename-session default-terrylica
zellij action dump-layout > /tmp/my-layout.kdl
zellij --layout default-terrylica
LaunchAgent Management
launchctl load ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
launchctl unload ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
launchctl list | grep zellij-save-layout
Protection Management
chflags uchg <file>
chflags nouchg <file>
ls -lO <file>
rm ~/.config/zellij/layouts/default-terrylica.kdl
AI Agent Interaction Guidelines
⚠️ CRITICAL: Do NOT Attempt to Delete
Protected file: ~/.config/zellij/layouts/default-terrylica.kdl
Why deletion will fail:
- File has
uchg immutable flag
- Standard
rm command returns: "Operation not permitted"
- This is INTENTIONAL protection, not an error
If Agent Needs to Update Layout
❌ DO NOT:
rm ~/.config/zellij/layouts/default-terrylica.kdl
echo "new layout" > ~/.config/zellij/layouts/default-terrylica.kdl
✅ DO THIS INSTEAD:
Option 1 - Use dedicated script (recommended):
save-zellij-layout
Option 2 - Manual flag handling:
chflags nouchg ~/.config/zellij/layouts/default-terrylica.kdl
zellij action dump-layout > ~/.config/zellij/layouts/default-terrylica.kdl
chflags uchg ~/.config/zellij/layouts/default-terrylica.kdl
Detection Pattern
When encountering "Operation not permitted" on a file:
ls -lO <file_path>
if ls -lO "$file" | grep -q "uchg"; then
echo "File is protected with immutable flag"
echo "Use save-zellij-layout or chflags to modify"
fi
Respect Patterns
Files with uchg flag are INTENTIONALLY protected. Agent should:
- Detect flag via
ls -lO
- Report: "File is immutable-protected"
- Suggest: "Use save-zellij-layout command"
- Do NOT attempt
sudo or force removal
- Do NOT suggest workarounds that bypass protection
File Locations
Primary Files
Layout file (protected):
- Path:
~/.config/zellij/layouts/default-terrylica.kdl
- Size: ~9KB
- Protection:
uchg immutable flag
- Updated: Every 5 minutes or on-demand
Update script:
- Path:
~/.local/bin/zellij-save-layout
- Purpose: Safely update protected layout
- Execution: Manual or via LaunchAgent
LaunchAgent:
- Path:
~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
- Interval: 300 seconds (5 minutes)
- Status: Active and running
Log Files
Success log: /tmp/zellij-save-layout.log
Layout saved and protected: ~/.config/zellij/layouts/default-terrylica.kdl
Error log: /tmp/zellij-save-layout.error.log
Zellij Session Cache
Zellij auto-saves to cache every 60 seconds:
~/Library/Caches/org.Zellij-Contributors.Zellij/0.43.1/session_info/default-terrylica/
├── session-layout.kdl
└── session-metadata.kdl
Our system copies from cache → persistent protected location.
Operational Workflows
Daily Use
-
Start Zellij with saved layout
zellij --layout default-terrylica
-
Work normally (add tabs, panes, etc.)
- Layout auto-saves every 5 minutes
-
Make critical changes
save-zellij-layout
-
Exit Zellij
- Session preserved in cache
- Layout protected from deletion
-
Next day: Restart
zellij --layout default-terrylica
Recovery Scenarios
Scenario 1: Accidental session exit
zellij --layout default-terrylica
Scenario 2: System crash/reboot
zellij --layout default-terrylica
Scenario 3: Need to manually edit layout
chflags nouchg ~/.config/zellij/layouts/default-terrylica.kdl
hx ~/.config/zellij/layouts/default-terrylica.kdl
chflags uchg ~/.config/zellij/layouts/default-terrylica.kdl
Troubleshooting
Auto-Save Not Running
Check status:
launchctl list | grep zellij-save-layout
If not listed:
launchctl load ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
Check logs:
tail -50 /tmp/zellij-save-layout.error.log
Layout Not Updating
Verify session name:
zellij list-sessions
Manual trigger:
save-zellij-layout
Check timestamp:
ls -lh ~/.config/zellij/layouts/default-terrylica.kdl
Cannot Delete File (Expected Behavior)
This is CORRECT - file is protected:
rm ~/.config/zellij/layouts/default-terrylica.kdl
chflags nouchg ~/.config/zellij/layouts/default-terrylica.kdl
rm ~/.config/zellij/layouts/default-terrylica.kdl
Configuration Tuning
Change Auto-Save Interval
Current: 5 minutes (300 seconds)
vim ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
<key>StartInterval</key>
<integer>300</integer> <!-- Change this -->
launchctl unload ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
launchctl load ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
Recommended intervals:
- 60 = 1 minute (frequent)
- 300 = 5 minutes (current, balanced)
- 600 = 10 minutes
- 1800 = 30 minutes
Stronger Protection (System Immutable)
For maximum protection (requires sudo to modify):
chflags nouchg ~/.config/zellij/layouts/default-terrylica.kdl
sudo chflags schg ~/.config/zellij/layouts/default-terrylica.kdl
Note: Requires updating script to use sudo for updates.
Technical Details
Zellij Config Settings
From ~/.config/zellij/config.kdl:
session_serialization true // Enable auto-save
serialize_pane_viewport true // Save pane viewports
scrollback_lines_to_serialize 10000 // Save scrollback
serialization_interval 60 // Cache update interval
BSD File Flags
macOS inherits BSD filesystem flags:
| Flag | Name | Protection | Who Can Remove |
|---|
uchg | User immutable | Delete/modify blocked | File owner |
schg | System immutable | Delete/modify blocked | Root only |
uappnd | User append-only | Only append allowed | File owner |
sappnd | System append-only | Only append allowed | Root only |
We use uchg because:
- Blocks AI agents and scripts
- Owner can update without sudo
- Standard across BSD/macOS
Layout File Format (KDL)
Sample structure:
layout {
cwd "/Users/terryli"
tab name=".claude" focus=true {
pane split_direction="vertical" {
pane command="claude" size="65%"
pane size="35%"
}
}
}
Security Notes
Protection Level
uchg flag protects against:
✅ Accidental rm commands
✅ AI agents (unless they know about uchg)
✅ Text editors overwriting
✅ > redirection overwrites
✅ Scripts without flag knowledge
uchg flag does NOT protect against:
❌ Intentional removal by file owner
❌ Root/sudo operations
❌ Agents explicitly coded to handle BSD flags
Why This Is Standard Practice
BSD file flags are 45+ years old (from 4.4BSD):
- Used in macOS system protection
- Standard across FreeBSD, OpenBSD, NetBSD
- Not a "trick" - it's documented filesystem feature
- Linux equivalent:
chattr +i (ext2/3/4 immutable attribute)
Examples
Example 1: Check Auto-Save Status
launchctl list | grep zellij-save-layout && \
ls -lhO ~/.config/zellij/layouts/default-terrylica.kdl && \
tail -5 /tmp/zellij-save-layout.log
Example 2: Manual Save After Changes
save-zellij-layout
ls -lh ~/.config/zellij/layouts/default-terrylica.kdl
Example 3: Test Protection
rm ~/.config/zellij/layouts/default-terrylica.kdl
ls -lO ~/.config/zellij/layouts/default-terrylica.kdl | grep uchg
Quick Reference Card
launchctl list | grep zellij-save-layout
ls -lhO ~/.config/zellij/layouts/default-terrylica.kdl
tail /tmp/zellij-save-layout.log
save-zellij-layout
zellij --layout default-terrylica
chflags uchg <file>
chflags nouchg <file>
ls -lO <file>
launchctl load ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
launchctl unload ~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
See Also
- Zellij config:
~/.config/zellij/config.kdl
- Session storage:
~/Library/Caches/org.Zellij-Contributors.Zellij/
- Update script:
~/.local/bin/zellij-save-layout
- LaunchAgent:
~/Library/LaunchAgents/com.terryli.zellij-save-layout.plist
Official documentation: