# Path policy (/docs/concepts/path-policy)



Path policy is how Bowline decides what under your workspace root follows you and what stays local. The default is workspace continuity: once you accept a root, every non-excluded file under it syncs as encrypted workspace state. You override the defaults with a `.bowlineignore` Path Policy File when a path needs to be excluded or explicitly included.

## The sync boundary is your workspace root [#the-sync-boundary-is-your-workspace-root]

The accepted workspace root, normally `~/Code`, is the sync boundary. Everything portable under that root follows you to every authorized device.

Repo, package, and monorepo boundaries do not limit default sync. A folder with no Git remote, a nested package inside a monorepo, and a plain non-repo directory all follow the same rule: if it lives under the accepted root and isn't excluded, it syncs. You don't mark projects, register repos, or draw boundaries inside the root for Bowline to carry your work.

## What syncs by default [#what-syncs-by-default]

Bowline classifies each path to carry it safely. Source and developer files sync; generated junk, dependencies, and caches stay local. This keeps `node_modules` off the wire while your real work travels.

| Path kind                                     | Default behavior                                             |
| --------------------------------------------- | ------------------------------------------------------------ |
| Source and developer files                    | Sync as encrypted workspace state.                           |
| `.env`, `.env.local`, `.env.*` under the root | Sync as per-key env state and rematerialize locally.         |
| `.git/` directories                           | Sync as Opaque Git State (encrypted bytes, never as Git).    |
| Generated folders                             | Regenerate locally or ignore; do not spread across machines. |
| Dependency folders                            | Regenerate locally or use a local cache.                     |
| Caches and logs                               | Stay local; never become canonical.                          |
| Explicitly `local-only` or `blocked` paths    | Stay on the machine that has them.                           |

For how Git state and `.env` files are handled in depth, see [Git and source control](/docs/concepts/git-and-source-control) and [env sync](/docs/concepts/env-sync).

## Ignore files are evidence, not authority [#ignore-files-are-evidence-not-authority]

Bowline reads `.gitignore` and similar ignore files as classification evidence, not as final sync authority. Being git-ignored tells Bowline a path is probably generated, but it doesn't decide that the path stays off your other machines.

Source-like state you keep out of Git still syncs. Local `.env` files, scratch notes, reproduction cases, and test fixtures are real work, so they follow you even when Git never sees them. A path stops syncing only when it's generated, a dependency, a cache, explicitly local-only, or blocked by safety or organization policy.

## The .bowlineignore Path Policy File [#the-bowlineignore-path-policy-file]

The `.bowlineignore` Path Policy File records explicit include and exclude policy for its directory subtree. It syncs as ordinary workspace state, so the policy travels with the project. Patterns are relative to the file's own directory, so a file under `~/Code/acme/web/.bowlineignore` matches paths within `~/Code/acme/web`.

There are two kinds of pattern:

* Plain patterns exclude paths from workspace sync.
* `!` patterns explicitly include paths and can override the built-in generated, dependency, and cache defaults.

This example excludes local-only paths and re-includes two paths Bowline would otherwise skip:

```text
# Patterns are relative to this file's directory.

# Exclude local-only scratch work from sync.
scratch/
notes/local-only.md

# Re-include a generated file that is really source you hand-edit.
!src/generated/icons.ts

# Re-include a vendored dependency you want to travel with the project.
!vendor/patched-lib/**
```

Path policy precedence runs from strongest to weakest: a hard safety block or organization policy, then `.bowlineignore`, then the built-in high-confidence defaults, then sync everything else. An `!` include can override the built-in defaults, but it can't override a hard safety block or organization policy. If a path looks like a secret or is blocked by your organization, an include won't force it onto the wire.

<Callout type="warn" title="Important">
  Path Policy Files affect Bowline sync only. They never change Git tracking,
  Git ignore rules, staging, commits, branches, or remotes. Editing
  `.bowlineignore` does not touch `.gitignore`, and editing `.gitignore` does
  not change what Bowline syncs.
</Callout>

## Including a previously excluded path [#including-a-previously-excluded-path]

Adding an `!` include for a path that wasn't syncing is a first import, handled conservatively. Bowline never resolves it with last-writer-wins.

1. If only one machine has the content, it syncs.
2. If multiple machines have identical content, it syncs.
3. If multiple machines have different local content, Bowline preserves every local copy and raises a [Sync Conflict](/docs/concepts/conflicts) for you to resolve.

After the import succeeds or the conflict resolves, that path becomes ordinary workspace state and follows the normal rules for its file type. There's no permanent "imported" mode.

## Excluding a previously synced path [#excluding-a-previously-synced-path]

Adding a plain exclude pattern for a path that was syncing changes future sync only. It's never a delete.

* New machines don't receive the path.
* Machines that already have it keep their local copy as unmanaged local state.
* Status reports that copy as excluded local state.

Cleanup is explicit. Bowline leaves existing local copies in place until you remove them yourself, so excluding a path can't lose work you still have on disk.

<Callout type="info">
  `bowline init` and scans never create a `.bowlineignore` in an existing
  workspace. Path Policy Files appear only when you write one, so accepting a
  root never rewrites your tree.
</Callout>

## Inspecting why a path syncs [#inspecting-why-a-path-syncs]

When you're unsure why a path is or isn't syncing, run `bowline explain <path>`. It reports the matched rule, the detected file type, the current classification, the storage mode, access flags, and the next safe actions, so you can see exactly which policy applied.

```bash
bowline explain ~/Code/acme/web/fixtures/demo.sqlite
```

Add `--json` for scriptable output, and see [status and health](/docs/concepts/status-and-health) for the broader picture across a workspace.

## Next steps [#next-steps]

* [Git and source control](/docs/concepts/git-and-source-control): how `.git/` syncs as Opaque Git State.
* [Env sync](/docs/concepts/env-sync): how `.env` files are imported, merged by key, and rematerialized.
* [Conflicts](/docs/concepts/conflicts): what happens when a first import diverges.
* [Setup recipes](/docs/concepts/setup-recipes): the `.bowlinesetup` file for preparing a fresh machine or agent.
* [CLI commands](/docs/cli/commands): the full command reference, including `bowline explain`.
