You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hosting preset keys are mixed into generated/mutated schemas with no clear ownership boundary. Re-applying or updating a preset is ambiguous, and Day-2 mutation (add host) does not share the same safety model as bootstrap (init). Naming is still host-specific (--host-preset, add host) even though the product direction is a generic preset surface (see #1447 — decided here).
Generalize the CLI surface to presets now; keep the v1 catalog hosts-only (vercel, netlify). Non-host packs (Supabase, Sentry, etc.) are follow-ups once this plumbing ships.
Surface
Canonical
Notes
Bootstrap flag
init --preset <id>
Replace/alias --host-preset / -H
Apply / refresh
arkenv preset apply <provider>
Idempotent; nuke-and-pave owned blocks
Remove
arkenv preset remove <provider>
Deletes owned blocks + related .env.example keys when safe
Legacy
arkenv add host
Deprecated alias → preset apply
init bootstraps an ArkEnv project (and may seed managed preset blocks + persist schema entry). Day-2 preset lifecycle does not ride init.
Desired behavior
Managed blocks
Preset-owned schema text is delimited by comments:
Strict layout: role-suffixed blocks as needed, e.g. vercel:server, vercel:client. User runs preset apply vercel / remove vercel; the CLI manages all blocks for that base id.
Refresh: nuke-and-pave everything between matching markers.
Composability: multiple presets may stack (one owned region set each) as long as keys do not collide.
Ownership & collisions (fail closed)
Outside markers = user-owned. Sacred.
If preset apply needs a key that already exists outside this preset’s blocks → fail with a clear resolution message (no silent skip, no AST “definition match”, no steal).
Cross-preset key collision → fail the same way.
Legacy unmarked keys (from older init / add host): also fail closed. User deletes unmarked keys, then re-runs apply. No heuristic adoption.
.env / .env.example
Append missing keys to .env.exampleonly if that file already exists.
Never write .env (secrets). Future --write-env is out of scope.
On remove: strip keys that preset owned from .env.example when ownership is clear; if cross-preset sharing of an example key is unclear, leave a stale empty key rather than risk breaking another preset.
Discovery
init persists an arkenv schema entry/root (including layout strategy) on the nearest package.json — not merely a single file path (must support flat and strict).
preset apply / remove read that pointer for zero-config Day 2.
Override with -f / --file (or equivalent schema path flag).
No path heuristics as the primary strategy for v1.
Git safety
Require a clean git working tree by default for preset apply / preset remove (and any writes they perform).
Bypass with --force.
Not a git repo → proceed. Unknown status → warn and proceed.
Malformed markers
If start/end markers are missing, unbalanced, or otherwise malformed → fail closed (especially on remove). Do not delete past an unmatched start marker.
Scope boundaries
preset apply / preset remove do not touch .gitignore or provider-specific dotfiles (.vercel, .netlify, …). Baseline .env ignores remain init-only.
v1 catalog:vercel, netlify only (plus any already-approved host ids if already in tree). No new SaaS/observability packs in this issue.
Does not require inventing a semantic validator AST differ across Zod / Valibot / ArkType.
preset remove does not remove the package.jsonarkenv workspace pointer.
Acceptance criteria
arkenv preset apply <provider> inserts or refreshes managed comment blocks for the provider (nuke-and-pave inside markers).
arkenv preset remove <provider> removes all blocks for that base id (including :server / :client suffixes) and updates .env.example per the rules above.
init --preset <id> seeds managed blocks and writes the package.jsonarkenv schema entry/root; --host-preset / -H remain as aliases or are clearly deprecated toward --preset.
arkenv add host remains as a deprecated alias of preset apply (or documented migration) without a second divergent code path long-term.
Multiple presets can coexist; key collisions (user-owned or cross-preset) fail closed with actionable errors.
Legacy unmarked colliding keys fail closed (no auto-adopt).
.env.example: append missing keys only if file exists; never touch .env.
Discovery uses package.jsonarkenv entry; -f overrides; no heuristics-first discovery.
Judgment-heavy work (especially migrating legacy unmarked preset keys to managed blocks, and collision triage) may be guided by the ArkEnv agent skill. The skill interprets CLI refusals and proposes safe next steps; it must not become a soft auto-adopt path that rewrites user-owned unmarked keys. Deterministic apply/remove/git gates stay in the CLI.
Problem
Hosting preset keys are mixed into generated/mutated schemas with no clear ownership boundary. Re-applying or updating a preset is ambiguous, and Day-2 mutation (
add host) does not share the same safety model as bootstrap (init). Naming is still host-specific (--host-preset,add host) even though the product direction is a generic preset surface (see #1447 — decided here).Decision summary (resolves #1447)
Generalize the CLI surface to presets now; keep the v1 catalog hosts-only (
vercel,netlify). Non-host packs (Supabase, Sentry, etc.) are follow-ups once this plumbing ships.init --preset <id>--host-preset/-Harkenv preset apply <provider>arkenv preset remove <provider>.env.examplekeys when safearkenv add hostpreset applyinitbootstraps an ArkEnv project (and may seed managed preset blocks + persist schema entry). Day-2 preset lifecycle does not rideinit.Desired behavior
Managed blocks
Preset-owned schema text is delimited by comments:
vercel).vercel:server,vercel:client. User runspreset apply vercel/remove vercel; the CLI manages all blocks for that base id.Ownership & collisions (fail closed)
preset applyneeds a key that already exists outside this preset’s blocks → fail with a clear resolution message (no silent skip, no AST “definition match”, no steal).init/add host): also fail closed. User deletes unmarked keys, then re-runs apply. No heuristic adoption..env/.env.example.env.exampleonly if that file already exists..env(secrets). Future--write-envis out of scope.remove: strip keys that preset owned from.env.examplewhen ownership is clear; if cross-preset sharing of an example key is unclear, leave a stale empty key rather than risk breaking another preset.Discovery
initpersists anarkenvschema entry/root (including layout strategy) on the nearestpackage.json— not merely a single file path (must support flat and strict).preset apply/removeread that pointer for zero-config Day 2.-f/--file(or equivalent schema path flag).Git safety
preset apply/preset remove(and any writes they perform).--force.Malformed markers
Scope boundaries
preset apply/preset removedo not touch.gitignoreor provider-specific dotfiles (.vercel,.netlify, …). Baseline.envignores remaininit-only.vercel,netlifyonly (plus any already-approved host ids if already in tree). No new SaaS/observability packs in this issue.preset removedoes not remove thepackage.jsonarkenvworkspace pointer.Acceptance criteria
arkenv preset apply <provider>inserts or refreshes managed comment blocks for the provider (nuke-and-pave inside markers).arkenv preset remove <provider>removes all blocks for that base id (including:server/:clientsuffixes) and updates.env.exampleper the rules above.init --preset <id>seeds managed blocks and writes thepackage.jsonarkenvschema entry/root;--host-preset/-Hremain as aliases or are clearly deprecated toward--preset.arkenv add hostremains as a deprecated alias ofpreset apply(or documented migration) without a second divergent code path long-term..env.example: append missing keys only if file exists; never touch.env.package.jsonarkenventry;-foverrides; no heuristics-first discovery.--force; non-repo OK; unknown warns.init.preset apply/preset remove, fail-closed collisions, and legacy unmarked→marked migration guidance. Skill reasons and prepares; CLI remains the authority for owned-region mutation (do not teach agents to bypass fail-closed apply)..env.exampleappend-only.Agent skill boundary
Judgment-heavy work (especially migrating legacy unmarked preset keys to managed blocks, and collision triage) may be guided by the ArkEnv agent skill. The skill interprets CLI refusals and proposes safe next steps; it must not become a soft auto-adopt path that rewrites user-owned unmarked keys. Deterministic apply/remove/git gates stay in the CLI.
Out of scope
.env/--write-env.gitignoremutation from apply/removeRelated