Skip to content

Isolation

Two runs of two different workflows shouldn't share files. The morning brief shouldn't see scratch files from the research sprint. The research sprint shouldn't notice when a coding workflow creates a new branch. Z.E.N. handles this by giving every run its own working directory.

The default behavior

When a workflow fires, Z.E.N. picks a working directory based on the project the run is against:

  • For workflows that don't touch git, the working dir is a fresh sandbox under ~/.zen/workspaces/.
  • For workflows that need a git context, Z.E.N. creates a git worktree at ~/.zen/worktrees/. The worktree is a separate working copy of the project, on its own branch.

Either way, the working dir is unique to the run. Two parallel runs of the same workflow get two different worktrees.

When isolation matters

The cases where you'll notice this:

  • Schedules. If yesterday's brief is still running when today's brief fires, the working-path lock kicks in. Today's fire records a skip; yesterday's keeps going on its own working dir.
  • Parallel workflows. Running three workflows in parallel that all touch the same project is safe because each one has its own working copy.
  • Coding workflows. A workflow that does git operations (commits, branches, PRs) does them on a worktree, not on your main checkout. You can keep working on the project while the workflow runs.

When isolation doesn't apply

Some workflows don't need a working directory at all. A workflow that just pulls Slack and posts to a channel doesn't touch files. Z.E.N. still allocates a working dir for state, but the dir is essentially empty.

You can disable worktree creation explicitly for a workflow that doesn't need one:

yaml
name: morning-brief
worktree:
  enabled: false

The run still gets a workspace, just not a git worktree.

The working-path lock

A separate primitive layered on top of isolation. The lock prevents two runs of the same workflow from colliding on the same working path:

  • If you fire morning-brief and the previous run is still going, the new fire is cancelled with status "Workflow already active on this path."
  • Schedules respect this. A scheduled fire that would step on an in-flight run gets recorded as a skip in skip_count and waits for the next tick.

If you genuinely want two parallel runs of different workflows on the same path, set concurrency.allowParallelWorkflows: true in .zen/config.yaml. The lock then scopes by (working_path, workflow_name) instead of just working_path, so different-name workflows on the same cwd run in parallel; same-name still blocks itself.

What you don't have to think about

You don't have to clean up worktrees. Z.E.N. has a cleanup loop that prunes old worktrees on a schedule.

You don't have to copy files into the worktree manually. If a workflow needs the project's source, the worktree is already a working copy of it.

You don't have to track which run owns which dir. That's a database row; the Dashboard and zen run list show it.

Configuration

The locations and the cleanup cadence are configurable, but the defaults are fine for most cases. See Configuration and Operate / Local if you want to change where worktrees land.

AI that follows a recipe, not a conversation.