Ownership & version control
What’s in a project directory
noemata init creates:
noemata.json— the project configuration. Committed.noemata.projects.json— the multi-project registry, when there is more than one project. Committed; it’s shared, repo-wide data.noemata.lock.json— the concrete versions of the managed service binaries this project installed (ClickHouse, the OpenTelemetry collector), recorded the first time each is provisioned. Commit it: it is what makes a teammate’snoemata upinstall the same versions yours did, rather than whatever the configured constraint resolves to that day. Delete an entry to let the nextupre-resolve it.@frames/— frame definitions, including everything installed by integrations.config/— generated configuration for Noemata-owned services (ClickHouse, the collector, the app)..env— the project’s secrets: the database credentials and the encryption key for session cookies. Written owner-readable (0600) and always gitignored. See The.envfile..data/— local, machine-specific state: logs, PIDs, generated JSON schemas, andtracked.json, which records the base of each path: the version the checkout last fetched or published. Always gitignored.
Binaries live outside the project, shared across every project on the machine: ~/.noemata/bin for the collector, ~/.clickhouse/versions for ClickHouse. Nothing there is project state — deleting it only means the next up downloads again.
Managed vs. user-owned packs
integrations.managed decides who owns the frame packs an integration installs under @frames/@<id>/.
true(the default) — Noemata-managed. Each pack is gitignored, and everynoemata up(ornoemata reconcile) overwrites it to match source, including any local edit. Extend a managed pack by reference instead of editing it in place — see Extend by reference.false— user-owned. A pack is seeded once, then left alone: your edits and deletions persist, and it’s tracked by git like any hand-authored frame.noemata up --managedre-syncs it from source when you want to pull in upstream changes (reviewable as a normalgit diff).
Ownership is per file rather than per directory. Reconcile tells a local change apart from an upstream one by comparing each file against what it last installed (recorded under .data/packs/), and each managed pack carries a generated @frames/@<id>/.gitignore naming exactly the files it installs — so anything else you add inside that directory (an overlay, a concrete route beside a parameterized one, a sibling dashboard) is version-controlled automatically, with no .gitignore edit of your own.
Customizing without forking
Two overlay file types let you retune an installed (or any) frame without editing it in place: a .local file for a change that’s only yours, and an .overrides file for one your team should have too. .local files are always gitignored; .overrides files are always committed, even inside a gitignored managed pack — so a team’s shared customization of a shipped dashboard stays in version control while reconcile keeps the base matching source underneath it.
That’s the ownership story; the exact merge rules — what an overlay can and can’t change, and how .overrides and .local layer together — are in Customizing an installed frame.
Beyond overlays, .local is a general naming convention: any file or directory whose name carries the .local token (notes.local, .local/) is yours — gitignored, so it never lands in a commit. Its deployment-scoped sibling is .shared (.shared/): system state that Noemata writes, such as current workflow state and deployment revisions. .shared paths are gitignored the same way and are never published. Noemata rejects a write to a .shared path that it does not own, so keep your own files under names without the marker.
Frame discovery excludes directories named .shared, including their frame, page, template, workflow, and Markdown files. Keep navigable content outside those directories; direct file-store access remains available for deployment state.