Skip to content

[Feat] Provision environments declaratively from files at startup - #26

Merged
brunobergher merged 2 commits into
developfrom
feature/declarative-environment-provisioning-0pvws3rizy1nm
Jul 9, 2026
Merged

[Feat] Provision environments declaratively from files at startup#26
brunobergher merged 2 commits into
developfrom
feature/declarative-environment-provisioning-0pvws3rizy1nm

Conversation

@roomote-roomote-v1

@roomote-roomote-v1 roomote-roomote-v1 Bot commented Jul 9, 2026

Copy link
Copy Markdown

Opened on behalf of Bruno Bergher. Follow up by mentioning @openmote, in the web UI, or in Slack.

What changed

Self-hosted deployments can now provision environments declaratively at startup, infrastructure-as-code style, instead of creating them through the web UI or the setup agent:

  • ROOMOTE_ENVIRONMENTS_DIR points at a mounted directory of environment definition files (*.yaml, *.yml, *.json), one environment per file.
  • ROOMOTE_ENVIRONMENTS_YAML accepts inline multi-document YAML for PaaS-style deployments (Railway/Render/Fly) where mounting files is awkward.

Definitions use exactly the same EnvironmentConfig YAML format as the environment editor's YAML view. The API applies the combined set on every boot (non-fatal, with the same advisory-lock + pending-migration retry pattern as the auth-keypair bootstrap):

  • Upsert by name, restricted to deployment-owned non-eval environments; user-owned or eval name collisions are skipped with a logged error.
  • The declarative definition wins on every boot. Environments stay editable in the UI — they show a "Managed from file" badge in Settings → Environments and a warning banner on the edit page — but edits are overwritten on the next restart. Every overwrite is recorded in config version history with the new file source.
  • Idempotent: identical re-applies are no-ops (no version churn, no environment-snapshot invalidation) via updateEnvironmentDefinition's existing diff.
  • Never prunes: removing a definition clears the declarative_source marker and returns the environment to normal manual management.
  • Missing repositories are tolerated: definitions can reference repos that are not linked yet (e.g. before the GitHub App is installed); repository mappings backfill automatically on the first boot after linking.
  • Failures are contained: invalid definitions are skipped with logged errors and surfaced to Sentry, and a missing or unreadable ROOMOTE_ENVIRONMENTS_DIR is skipped the same way, so inline ROOMOTE_ENVIRONMENTS_YAML definitions still apply. Nothing blocks API startup.
  • Orphan reconciliation is conservative: markers are only cleared when the entire declared set was read and validated successfully. While any definition fails to read or parse, reconciliation is deferred (orphaningDeferred), so a temporary typo in a still-present file never strips its environment's managed marker.

Supporting changes:

  • Schema migration: nullable environments.declarative_source, and environments.created_by_user_id is now nullable to represent system provisioning. The scheduled snapshot-refresh job now falls back to the first active user for job attribution when an environment has no creating user.
  • ROOMOTE_ENVIRONMENTS_DIR/ROOMOTE_ENVIRONMENTS_YAML are added to the control-plane env var denylist (reserved from the env-var editor, stripped from task sandboxes) and forwarded through docker-compose.self-host.yml.
  • Dogfood: Roomote's own environment definition is checked in at .roomote/environments/roomote.yaml as a living example, with a schema-freshness test so it can never drift from environmentConfigSchema.
  • Docs: new SELF_HOSTING.md section, public docs updates (environments.mdx, environment-variables.mdx), and .agent-guidance/features/environment-management.md coverage of the new write path.

Why this change was made

Teams that treat Roomote deployments as cattle want fully working environments without human intervention, environment definitions kept in git (so agents can maintain them alongside code changes), and fast dev-environment resets. Environments were previously only creatable through browser-session-gated UI flows or the setup agent.

Impact

Operators can bring up a deployment with its environments defined entirely in version-controlled files, keep them in sync via redeploys, and restore local dev environments after a DB reset with one env var (ROOMOTE_ENVIRONMENTS_DIR=$PWD/.roomote/environments pnpm dev). Existing UI/agent environment management is unchanged; declaratively provisioned environments are clearly badged but stay editable. Verified end-to-end against a live dev database: first apply created the Roomote environment from the dogfood file, second apply reported unchanged.

Screenshots

Settings → Environments list showing the "Managed from file" badge next to the declaratively provisioned Roomote environment

Edit page for the declaratively provisioned environment showing the warning banner that the file definition overwrites edits on restart

@roomote-roomote-v1

roomote-roomote-v1 Bot commented Jul 9, 2026

Copy link
Copy Markdown
Author

No code issues found. See task

  • packages/db/src/lib/declarative-environments.ts:293 Contain directory read failures so a bad ROOMOTE_ENVIRONMENTS_DIR is skipped instead of aborting the whole declarative apply. readDefinitionsFromDir() lets readdir() throw before inline YAML is read, so when both inputs are configured a stale or missing mounted directory prevents valid ROOMOTE_ENVIRONMENTS_YAML definitions from applying and also prevents the loader from reconciling the rest of the valid set.
  • packages/db/src/lib/declarative-environments.ts:541 Do not orphan existing managed environments just because their current definition failed parsing or schema validation. declaredNames is built only from successfully validated definitions, then clearOrphanedDeclarativeMarkers() clears markers for every declarative environment outside that list; a transient typo in a still-present file removes the badge and warning, and if all files are invalid it clears all declarative markers even though no definitions were actually removed.

@roomote-roomote-v1

roomote-roomote-v1 Bot commented Jul 9, 2026

Copy link
Copy Markdown
Author

Fixed both outstanding review issues in f4ebc64:

  1. Bad ROOMOTE_ENVIRONMENTS_DIR no longer aborts the apply. A missing or unreadable definitions directory is contained as a skip entry (source ROOMOTE_ENVIRONMENTS_DIR), so inline ROOMOTE_ENVIRONMENTS_YAML definitions and the rest of the valid set still apply.
  2. Invalid definitions no longer clear declarative markers. Orphan reconciliation now runs only when the entire declared set was read and validated successfully; any read/parse/schema failure defers it (orphaningDeferred: true in the apply summary), so a transient typo in a still-present file keeps its environment's badge and warning, and an all-invalid set clears nothing.

Both behaviors are covered by new real-database tests (applies inline YAML even when the definitions directory is unreadable, keeps declarative markers when a still-present definition fails to parse); the full loader suite (14 tests), lint, and typecheck pass. SELF_HOSTING.md and the internal guidance doc were updated to document the contained-failure and deferred-reconciliation semantics, and the PR description reflects the new behavior. These fixes are non-visual loader behavior, so no new screenshots; the existing UI proof in the PR body is unchanged and still current. See task

@brunobergher
brunobergher marked this pull request as ready for review July 9, 2026 12:34
@brunobergher
brunobergher merged commit 3e79fe3 into develop Jul 9, 2026
brunobergher pushed a commit that referenced this pull request Jul 9, 2026
* feat: provision environments declaratively from files at startup

* fix: contain declarative dir failures and defer orphaning on invalid definitions

---------

Co-authored-by: Roomote <roomote@roomote.dev>
@mrubens
mrubens deleted the feature/declarative-environment-provisioning-0pvws3rizy1nm branch July 12, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants