# Adopt standard .plane/ root directory convention for Project-as-Code (Plane Compose / CLI)

**URL:** <https://forum.plane.so/t/adopt-standard-plane-root-directory-convention-for-project-as-code-plane-compose-cli/316>\
**Category:** Feature requests\
**Created:** [September 2, 2026, 10:52pm UTC](https://forum.plane.so/t/adopt-standard-plane-root-directory-convention-for-project-as-code-plane-compose-cli/316 "2026-09-02T22:52:52Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![amirakrari](https://forum.plane.so/letter_avatar_proxy/v4/letter/a/58f4c7/32.png) [@amirakrari](https://forum.plane.so/u/amirakrari)\
**Post date:** [September 2, 2026, 10:52pm UTC](https://forum.plane.so/t/adopt-standard-plane-root-directory-convention-for-project-as-code-plane-compose-cli/316/1 "2026-09-02T22:52:52Z")

</div>

(written with help of AI)  
First off, huge appreciation to the Plane team for building “Project-as-Code” (Plane Compose / CLI). Having issue tracking, cycles, pages, and workflows version-controlled alongside code is an incredible direction for developer-centric project management.

I wanted to open a discussion and feature proposal regarding the directory structure created by the Plane CLI when cloning or initializing a project inside an existing repository.

### Background & Context

About 7 months ago, I had a brief chat with one of the Plane developers and shared initial feedback regarding this directory convention. They kindly mentioned they would pass the thought along to the core team.  
I’m bringing it to the community forum now simply to ensure the feedback isn’t lost, to see if other teams feel the same friction, and to offer concrete suggestions on how we could align with standard developer tooling conventions.

### The Problem

When running `plane clone` or initializing a project within the root of an existing repository, the CLI currently creates a top-level directory named after the project key/identifier (for example, in our case, an `event/` folder for project key `EVENT`).

Inside this project-named folder, we get:  
```text  
event/  
├── .gitignore  
├── .plane/ (internal CLI state: state.json, state.lock)  
├── plane.yaml  
├── workspace.yaml  
├── schema/  
└── work/

While this works well if Plane is treated as an isolated standalone repository, it causes significant friction when embedding Project-as-Code into an **existing application or monorepo** :

1. **Naming Collisions with Domain/Source Code** :  
Project keys often match the domain or product name (e.g., `event`, `billing`, `core`, `api`). Having a folder named `event/` at the repository root directly clashes with source code folders, microservice boundaries, or domain libraries.
2. **Root Clutter** :  
It adds an un-namespaced, visible top-level folder to the repository root that looks like application code rather than tooling configuration.
3. **Divergence from Ecosystem Conventions** :  
Modern developer tooling unanimously follows the dot-folder convention (`.<tool>/`) at the repository root to encapsulate project-level tool metadata and configurations:
  - `.github/` (GitHub Actions, templates)
  - `.gitlab/` (GitLab CI/CD)
  - `.vscode/` or `.idea/` (IDE settings)
  - `.claude/`, `.cursor/`, `.omo/` (AI agent configs & rules)
  - `.devcontainer/`, `.husky/`, `.terraform/`

* * *

### Proposed Solution

Encapsulate all Plane Project-as-Code files inside a dedicated dot-directory at the repository root: **`.plane/`**.

#### 1. Ideal Structure (Single Project):

When cloning or initializing in the root of an existing project:

```plaintext
my-repo/
├── .plane/
│ ├── plane.yaml
│ ├── workspace.yaml
│ ├── schema/
│ ├── work/
│ └── cache/ (or internal state)
├── src/
├── tests/
└── README.md

```

#### 2. Monorepo / Multi-Project Support:

If a repository links to multiple Plane projects:

```plaintext
my-repo/
└── .plane/
    ├── workspace.yaml
    └── projects/
        ├── event/
        │ ├── plane.yaml
        │ └── ...
        └── billing/
            ├── plane.yaml
            └── ...

```

#### 3. CLI Ergonomics:

At minimum, even if the default behavior is preserved for backwards compatibility, providing an explicit target path or flag would solve this immediately:

```bash
# Clone directly into .plane in current directory
plane clone <PROJECT_KEY> --path .plane
# or
plane init --dir .plane

```

* * *

### Why this matters

Embracing the `.plane/` convention makes Plane feel like a native citizen in modern codebases. Developers and teams can commit their Project-as-Code setup without interfering with existing build systems, file trees, or package layouts.

---

<div class="post-metadata">

**Author:** ![manish](https://forum.plane.so/letter_avatar_proxy/v4/letter/m/a6a055/32.png) [@manish](https://forum.plane.so/u/manish)\
**Post date:** [September 3, 2026, 7:32am UTC](https://forum.plane.so/t/adopt-standard-plane-root-directory-convention-for-project-as-code-plane-compose-cli/316/2 "2026-09-03T07:32:52Z")

</div>

Hello @amirakrari

Really appreciate you bringing this back – sounds like the note from that hallway  
conversation 7 months ago never made it into anything trackable, which is exactly the  
kind of thing that happens to feedback that only lives in a conversation. Glad it’s  
written up properly here now.

## On the dot-folder convention

Most of the examples you listed – `.github/`, `.devcontainer/`, `.husky/`, `.vscode/` –  
actually hold content people author by hand and review in PRs (workflow YAML, hook  
scripts, devcontainer configs), so “dot-folder” clearly doesn’t mean “hidden internal  
state only” across the ecosystem generally. Fair to say the pattern is really “this is  
the tool’s namespace,” not a statement about what’s allowed to live inside it – so we’re  
not going to argue the convention itself doesn’t apply here.

Where we’d add a data point of our own: `.git/` and `.terraform/` specifically (not on  
your list, but worth looking at too) follow a _stricter_ version of it – the dot-folder  
there holds only derived/internal state (`.git/objects`, `.terraform`’s provider  
binaries and module cache), and the content a person actually authors – your source  
tree, your `.tf` files – stays in plain view at the root, never inside it. Plane Compose  
already mirrors that narrower pattern one level down today: `<project>/.plane/` holds  
internal state (`state.json`, the lock file), while `plane.yaml`/`schema/`/`work/` – the  
stuff you actually edit and review – sit visibly beside it.

The practical reason we’d lean toward keeping it that way isn’t really a purity argument  
about what dot-folders are “for” – plenty of tools put real content in them, as your own  
list shows. It’s that dot-directories commonly get treated as hidden-by-default by  
tooling that walks a repo: `ls` without `-a`, some editor sidebars, some `find`/linter  
invocations. That’s a fine tradeoff for a CI workflow file you configure once and rarely  
open. It’s more friction for `schema/`/`work/`, which is meant to be routinely browsed  
and edited by the whole team, closer to source than to one-time config. So the caution  
is about discoverability for files people touch often, not a claim that dot-folders are  
off-limits for real content in general.

## The actual problem is real – but I think it splits into two different setups that want two different answers

`event/` colliding with a domain folder called `event/` isn’t really about `event/`  
being too _visible_ – it’s about it having no namespace of its own at the repo root.  
That’s a different problem than the one dot-folders solve. But “give it a namespace”  
means something different depending on what kind of repo you’re actually embedding into,  
and your post reads like it could be either:

**If this is one repo per project** (which is what your concrete example – one `event/`  
folder for project key `EVENT` – sounds like): the fix is just naming the one folder  
something that doesn’t collide, nothing more. `plane clone EVENT --directory <name>`  
already does this today – rename it to `plane-event/`, `.event-plane/`, whatever avoids  
the clash in your tree, no design work needed on our end. (If you do pick something  
dot-prefixed, worth noting given the section above: it’s not hiding anything the way  
`.git` hides its internals – `plane.yaml`/`schema/`/`work/` are still sitting right there  
inside it, just under a renamed folder. There’s also a rough edge if you land on `.plane`  
specifically – the internal state folder is _also_ named `.plane/` inside whatever you  
pick, so that exact combination nests as `.plane/.plane/` – we’ll clean that up  
regardless.) What this setup should _not_ do is pull in workspace-level config (via  
`ws clone`) alongside it – if every project repo carries its own independent copy of the  
workspace schema, edited and pulled on its own schedule, you get config drift across  
repos instead of the collision problem you have now. One project, one folder, no  
workspace nesting.

**If this is a true monorepo** – one repo that’s meant to hold every project under a  
workspace, code included – namespacing under a workspace folder makes more sense, and  
this is where something like `ws clone` nesting projects underneath it earns its keep:

```plaintext
my-repo/
├── acme-workspace/ ← `plane ws clone acme-workspace`
│ ├── schema/ (workspace-level config, one copy)
│ └── projects/
│ ├── event/ ← `plane clone EVENT`, nested here instead of at root
│ └── billing/ ← same for another project
├── apps/
│ └── event/ ← your actual "event" domain code -- no longer collides
└── README.md

```

The `projects/` layer isn’t just tidiness – anywhere our own code walks a workspace  
folder looking for `schema/*.yaml`, a project folder sitting as a direct sibling of  
`schema/` risks getting swept into that scan and having its YAML misread as workspace  
config. Keeping projects in their own subtree avoids that ambiguity outright instead of  
relying on filename conventions.

This model has a real limit worth naming rather than glossing over: it only holds until  
any one project in that workspace lives outside this repo. At that point that project  
either doesn’t get a local clone here at all, or gets its own standalone `plane clone`  
elsewhere – which drops it back into the single-project-repo case above, drift risk and  
all. We think that’s an acceptable edge rather than something to design around – not  
every project in a workspace has to be tracked the same way.

If this direction goes anywhere, one ergonomics question it raises: should  
`plane clone EVENT` in a repo with no workspace folder yet auto-run the equivalent of  
`ws clone` first and nest itself inside, rather than making that a separate manual step?  
Leaning toward yes for the monorepo case specifically, but this is very much still an  
open question, not a decision.

To be clear on where this stands: the monorepo/nesting piece is a direction we’re  
thinking about, not a plan with a date. The single-project-repo fix is closer – mostly  
already possible via `--directory`, and `plane init`/`plane ws clone` not having the same  
flag yet is a real, fixable gap independent of anything above.
