Skip to content

Replace app env management with better-env#17

Merged
andrelandgraf merged 8 commits intomainfrom
codex/better-env-migration
Feb 21, 2026
Merged

Replace app env management with better-env#17
andrelandgraf merged 8 commits intomainfrom
codex/better-env-migration

Conversation

@andrelandgraf
Copy link
Contributor

@andrelandgraf andrelandgraf commented Feb 21, 2026

Summary

  • add better-env to the app and configure Vercel sync in app/better-env.ts
  • replace the zod-only env parser with better-env/config-schema in app/src/lib/main/config.ts
  • keep the existing mainConfig API by re-exporting from app/src/lib/config.ts
  • add app scripts for env pull/validation and a preview build verification path
  • bump better-env to latest (0.3.1) in app manifests/lockfiles

Verification

  • bun run env:pull:preview
  • bun run env:validate
  • bun run env:validate:production
  • bun run env:validate:preview
  • bun run build:preview
  • bunx skills update -y (result: all skills up to date)

Preview Deployment Check

  • attempted deploy with vercel deploy --target=preview --yes
  • preview URL: https://app-98xazg9gz-andrelandgraf.vercel.app
  • status: Error
  • failure is unrelated to env migration and occurs during Next.js typecheck at src/app/[slug]/dashboard/before-start-dashboard.tsx:64 (eq(hack.event_id, event.id) overload mismatch)

Notes

  • preview validation uses bun --env-file=.env.preview ... --environment production as a workaround for a better-env@0.3.x CLI limitation with NODE_ENV=preview.

Summary by CodeRabbit

  • New Features
    • Integrated environment management with runtime sync, validation, and a preview build pathway.
  • Chores
    • Updated dev/build flows to validate environment configuration before running.
    • Centralized application configuration exports to a shared config module.
  • Documentation
    • Added comprehensive docs and skill guides for environment management, adapters, CLI usage, validation, observability, testing, auth, chat, and other recipes.

@cursor
Copy link

cursor bot commented Feb 21, 2026

You have run out of free Bugbot PR reviews for this billing cycle. This will reset on March 8.

To receive reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

@vercel
Copy link

vercel bot commented Feb 21, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
allthingsweb Ready Ready Preview, Comment Feb 21, 2026 11:44pm

Request Review

@coderabbitai
Copy link

coderabbitai bot commented Feb 21, 2026

Warning

Rate limit exceeded

@andrelandgraf has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 19 minutes and 12 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Adds Better-Env integration and CLI scripts, introduces a centralized runtime configuration module, re-exports config from the new module, and adds many skill/reference documentation files plus a skills lockfile.

Changes

Cohort / File(s) Summary
Better-Env entry
app/better-env.ts
New module exporting a configured Better-Env instance using the Vercel adapter and mapping five environments to env files/remote names.
Package scripts & dependency
app/package.json
Adds better-env dependency and env management scripts (env:pull:*, env:validate*), updates dev to run validation, updates build to validate production, and adds build:preview.
Runtime configuration (new)
app/src/lib/main/config.ts
New central config module defining env schema, resolveOrigin helper, and exported mainConfig and MainConfig with instance, database, electricSQL, s3, resend, and luma sections.
Config re-export
app/src/lib/config.ts
Replaced local config construction with re-exports: mainConfig and MainConfig now re-exported from ./main/config.
Docs & skills
.agents/skills/..., .agents/skills/.../references/* (multiple files, see changes)
Adds numerous skill and reference Markdown docs for better-env, env-management, auth, testing, observability, and other skills; includes CLI and runtime references for better-env. (Pure documentation additions.)
Skills lockfile
skills-lock.json
New JSON lock describing the catalog/versioned registry of skills.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer/CLI
  participant BE as better-env (app/better-env.ts)
  participant Vercel as Vercel API/CLI
  participant FS as Local FS (.env files)
  participant Config as app/src/lib/main/config.ts

  Dev->>BE: run "env:pull:<env>" / "env:validate"
  BE->>Vercel: request environment vars (via vercel adapter)
  Vercel-->>BE: returns env key/value pairs
  BE->>FS: write to target .env file (unless remote null)
  BE->>FS: ensure .gitignore entry (if enabled)
  Dev->>Config: run application / build (imports config modules)
  Config-->>Config: parse/validate env schema (throws on missing/invalid)
  Config-->>Dev: app starts or build fails on validation error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I hop through keys and tiny dots,

I stitch the vars in tidy knots,
From local burrow to Vercel sky,
I nudge the files and watch them fly,
A carrot-coded cheer — configs align, oh my!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Replace app env management with better-env' accurately summarizes the primary change: migrating environment management from Zod-only to better-env integration with Vercel sync, while maintaining the existing mainConfig API.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/better-env-migration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/better-env.ts`:
- Around line 1-12: The import of defineBetterEnv and vercelAdapter is failing
because the package "better-env" is not declared or its API doesn't match this
usage; either add the correct dependency to package.json (install the published
package that exports defineBetterEnv and vercelAdapter) or update the import to
the actual package/API you intend to use; verify the module name and exported
symbols (defineBetterEnv, vercelAdapter) match the installed package and then
run npm/yarn install and update package.json so the build environment has the
dependency available.

In `@app/package.json`:
- Line 10: The npm script "env:validate:preview" currently runs validation
against the "production" schema, so preview-specific required vars from
better-env.ts are not validated; add a concise inline comment next to the
"env:validate:preview" script in package.json explaining this limitation (that
it's a CLI workaround and preview schema isn't exercised) and point to
better-env.ts as the authoritative preview schema so future maintainers know why
preview vars won't be caught and can revisit when the CLI supports it.
- Around line 6-11: Replace the hardcoded ./node_modules/better-env/dist/cli.js
invocations in the npm scripts (env:pull:development, env:pull:preview,
env:pull:production, env:validate, env:validate:preview,
env:validate:production) with the published CLI command bnv (i.e., use bnv
<subcommand> or npx/bunx bnv for portability) so package upgrades won’t break;
also correct the env:validate:preview script to use --environment preview
instead of --environment production. Ensure each script uses the bnv command and
the preview script’s --environment flag matches its name.

In `@app/src/lib/main/config.ts`:
- Around line 68-78: resolveOrigin currently checks envConfig.server.vercelUrl
before envConfig.server.origin, causing ORIGIN to be ignored on Vercel; change
the logic in the resolveOrigin function to first return envConfig.server.origin
if present, then if not present return `https://${envConfig.server.vercelUrl}`
when envConfig.server.vercelUrl exists, and finally fall back to
`http://localhost:${envConfig.server.port}`; update the branches that reference
envConfig.server.origin, envConfig.server.vercelUrl, and envConfig.server.port
accordingly so ORIGIN takes precedence over VERCEL_URL.

Comment on lines 1 to 12
import { defineBetterEnv, vercelAdapter } from "better-env";

export default defineBetterEnv({
adapter: vercelAdapter(),
environments: {
development: { envFile: ".env.development", remote: "development" },
preview: { envFile: ".env.preview", remote: "preview" },
production: { envFile: ".env.production", remote: "production" },
test: { envFile: ".env.test", remote: null },
local: { envFile: ".env.local", remote: null },
},
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, check if better-env package exists and find its structure
find node_modules/better-env -type f \( -name "*.d.ts" -o -name "*.ts" -o -name "*.json" \) 2>/dev/null | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

# Look for type definitions and main entry point
ls -la node_modules/better-env/ 2>/dev/null | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

# Check package.json to understand the structure
cat node_modules/better-env/package.json 2>/dev/null | head -50

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

# Check if better-env is in package.json and its version
cat package.json 2>/dev/null | grep -A 5 -B 5 "better-env" || echo "Not found in package.json"

Repository: allthingsweb-dev/allthingsweb

Length of output: 98


🏁 Script executed:

# Also check lock files
cat package-lock.json 2>/dev/null | grep -A 3 "better-env" | head -20 || echo "No package-lock.json or not found"

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🌐 Web query:

better-env @0.3.0 API defineBetterEnv vercelAdapter documentation

💡 Result:

I couldn’t find any public documentation for a better-env npm package v0.3.0 that exposes an API named defineBetterEnv or an adapter named vercelAdapter (searching those identifiers turns up no matches).

What I did find that’s close (but appears to be different software):

  • better-env.dev documents “better-env” as an encrypted-secrets CLI tool, not a TypeScript/JS runtime env-validation library—its docs describe managing secrets via .better-env files and runtime loading, and don’t mention defineBetterEnv/vercelAdapter. [1]
  • vercelAdapter() is documented as part of Vercel Flags / Flags SDK, provided by @flags-sdk/vercel, where it reads the FLAGS environment variable and initializes lazily. [2]

If you share a link to the repo/npm page for the exact better-env@0.3.0 you mean (or paste its README / type definitions for defineBetterEnv), I can point you to the correct API docs and usage.

Sources: [1] [2]


🏁 Script executed:

# Check if the file exists
ls -la app/better-env.ts 2>/dev/null || echo "File not found at app/better-env.ts"

Repository: allthingsweb-dev/allthingsweb

Length of output: 138


🏁 Script executed:

# Search for any better-env imports or references in the codebase
rg "better-env" --type ts --type tsx --type js --type json -i 2>/dev/null || echo "No better-env references found"

Repository: allthingsweb-dev/allthingsweb

Length of output: 103


🏁 Script executed:

# Check the actual app directory structure
ls -la app/ 2>/dev/null | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 1287


🏁 Script executed:

# Read the actual file to verify it matches the review comment
cat -n app/better-env.ts

Repository: allthingsweb-dev/allthingsweb

Length of output: 612


🏁 Script executed:

# Check if better-env might be a local/private package or part of a monorepo
find . -type d -name "better-env" 2>/dev/null | head -10

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

# Check for a packages or libs directory that might contain better-env
ls -la 2>/dev/null | grep -E "packages|libs|workspaces" || echo "No monorepo packages dir found"

Repository: allthingsweb-dev/allthingsweb

Length of output: 103


🏁 Script executed:

# Check package.json for any workspaces configuration
cat package.json 2>/dev/null | grep -A 5 -B 5 "workspaces\|packages"

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

# Also check if better-env is maybe aliased or imported from somewhere else
rg "export.*better-env\|export.*defineBetterEnv\|export.*vercelAdapter" --type ts --type tsx 2>/dev/null || echo "Not found"

Repository: allthingsweb-dev/allthingsweb

Length of output: 82


The better-env package is missing from the project's dependencies and has no publicly documented API matching this usage. The import of better-env will fail at runtime. Confirm whether this package should be added to package.json, or if the import path and/or API names are incorrect. If using a private/internal package, ensure it is properly declared as a dependency in package.json and available in the build environment.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/better-env.ts` around lines 1 - 12, The import of defineBetterEnv and
vercelAdapter is failing because the package "better-env" is not declared or its
API doesn't match this usage; either add the correct dependency to package.json
(install the published package that exports defineBetterEnv and vercelAdapter)
or update the import to the actual package/API you intend to use; verify the
module name and exported symbols (defineBetterEnv, vercelAdapter) match the
installed package and then run npm/yarn install and update package.json so the
build environment has the dependency available.

app/package.json Outdated
Comment on lines 6 to 11
"env:pull:development": "bun ./node_modules/better-env/dist/cli.js pull --environment development",
"env:pull:preview": "bun ./node_modules/better-env/dist/cli.js pull --environment preview",
"env:pull:production": "bun ./node_modules/better-env/dist/cli.js pull --environment production",
"env:validate": "bun ./node_modules/better-env/dist/cli.js validate --environment development",
"env:validate:preview": "bun --env-file=.env.preview ./node_modules/better-env/dist/cli.js validate --environment production",
"env:validate:production": "bun ./node_modules/better-env/dist/cli.js validate --environment production",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat app/node_modules/better-env/package.json | jq '.bin'

Repository: allthingsweb-dev/allthingsweb

Length of output: 145


🏁 Script executed:

sed -n '6,11p' app/package.json

Repository: allthingsweb-dev/allthingsweb

Length of output: 715


🏁 Script executed:

ls -la app/node_modules/better-env/ 2>/dev/null | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

cat app/package.json | jq '.dependencies, .devDependencies' | head -30

Repository: allthingsweb-dev/allthingsweb

Length of output: 1263


🌐 Web query:

better-env npm package bin entry

💡 Result:

If you’re publishing an npm package that should install the better-env CLI command, note that the tool’s documented command name is bnv (e.g., bnv setup, bnv run ...) [2]. To expose that command from an npm package, add a bin entry in package.json that maps the command name to your executable file [1]:

{
  "name": "better-env",
  "bin": {
    "bnv": "./bin/bnv.js"
  }
}

Or, if you want the command name to be the package name, you can use the string form (npm will use "name" as the command) [1]:

{
  "name": "better-env",
  "bin": "./bin/bnv.js"
}

Make sure ./bin/bnv.js starts with a Node shebang line (required for npm-installed CLI scripts) [1]:

#!/usr/bin/env node

Result: npm will link the command into ./node_modules/.bin/ for local installs and into the global prefix’s bin directory for global installs [1].

Sources: npm package.json bin field docs [1], better-env CLI docs showing bnv usage [2].


🏁 Script executed:

cat app/package.json | jq '.dependencies + .devDependencies | to_entries | map(select(.key | contains("env"))) | from_entries'

Repository: allthingsweb-dev/allthingsweb

Length of output: 101


🌐 Web query:

better-env npm registry package latest version

💡 Result:

The npm package better-env’s latest published version is 0.0.1. [1]

Source: libraries.io (npm package metadata mirror). [1]

References:
[1] (libraries.io)

Citations:


🌐 Web query:

"better-env" npm package javascript environment variables

💡 Result:

better-env is not a typical JavaScript “read env vars” library (like dotenv); it’s a CLI for managing secrets/env vars in an encrypted, per-user global store (OpenPGP) and injecting them only at runtime so you don’t keep plaintext .env files in repos. [1]

How you use it with a Node/JS app

  • One-time setup: bnv setup (creates/configures your OpenPGP key) [1]
  • Store a secret globally: bnv store KEY [1]
  • Link secrets to a project (creates/uses a .better-env file that lists which keys to load):
    • bnv init
    • bnv add KEY [1]
  • Run your JS app with env injected:
    • Interactive subshell: bnv shell → then run node … / npm run … inside it [1]
    • One-off command: bnv run node server.js (docs show bnv run … for executing a command with injected secrets) [1]

Installation note

The official docs show install via platform scripts (curl/PowerShell), not npm install. [1]
(Separately, there is an npm entry better-env@0.0.1 indexed on Libraries.io, but that’s just metadata and doesn’t reflect the docs’ recommended install path.) [2]

If you meant an npm package for parsing/validating process.env inside code, one example is good-env (type conversion, defaults, validation). [3]

Sources: [1] [2] [3]


🌐 Web query:

better-env npm package bin CLI executable

💡 Result:

The better-env npm package installs a CLI executable named bnv (not better-env). You run it like:

  • Local install: ./node_modules/.bin/bnv … (or just bnv … inside npm run scripts)
  • Without installing: npx bnv …

The bnv command is shown throughout the official docs (e.g., bnv setup, bnv init, bnv run …). [1]

Under the hood, this is done via npm’s package.json bin field, which maps a command name (here: bnv) to a script that npm links into your PATH (globally) or into node_modules/.bin (locally). [2]

Sources: [1] [2]


🌐 Web query:

site:npmjs.com better-env

💡 Result:

better-env appears to be a secrets-management CLI (an alternative to plaintext .env files) that stores secrets in a per-user encrypted global store using OpenPGP and injects them at runtime; projects use a commit-safe .better-env selector file. [1][2]

Package metadata indicates an npm package named better-env exists, with at least version 0.0.1 (installable as npm install better-env@0.0.1). [3]

Sources: [1] [2] [3]


Fix hardcoded dist path and use the published bnv command instead.

All CLI invocations hardcode ./node_modules/better-env/dist/cli.js. If the package reorganizes its dist structure between versions, this silently breaks every env script. The better-env package exposes a bin entry mapped to the bnv command; use that instead. Within npm scripts, simply use bnv <cmd>, or use npx bnv / bunx bnv for one-off runs.

Additionally, line 10 uses --environment production when the script is named env:validate:preview — this should likely be --environment preview.

♻️ Proposed refactor
-    "env:pull:development": "bun ./node_modules/better-env/dist/cli.js pull --environment development",
-    "env:pull:preview": "bun ./node_modules/better-env/dist/cli.js pull --environment preview",
-    "env:pull:production": "bun ./node_modules/better-env/dist/cli.js pull --environment production",
-    "env:validate": "bun ./node_modules/better-env/dist/cli.js validate --environment development",
-    "env:validate:preview": "bun --env-file=.env.preview ./node_modules/better-env/dist/cli.js validate --environment production",
-    "env:validate:production": "bun ./node_modules/better-env/dist/cli.js validate --environment production",
+    "env:pull:development": "bunx bnv pull --environment development",
+    "env:pull:preview": "bunx bnv pull --environment preview",
+    "env:pull:production": "bunx bnv pull --environment production",
+    "env:validate": "bunx bnv validate --environment development",
+    "env:validate:preview": "bun --env-file=.env.preview bunx bnv validate --environment preview",
+    "env:validate:production": "bunx bnv validate --environment production",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"env:pull:development": "bun ./node_modules/better-env/dist/cli.js pull --environment development",
"env:pull:preview": "bun ./node_modules/better-env/dist/cli.js pull --environment preview",
"env:pull:production": "bun ./node_modules/better-env/dist/cli.js pull --environment production",
"env:validate": "bun ./node_modules/better-env/dist/cli.js validate --environment development",
"env:validate:preview": "bun --env-file=.env.preview ./node_modules/better-env/dist/cli.js validate --environment production",
"env:validate:production": "bun ./node_modules/better-env/dist/cli.js validate --environment production",
"env:pull:development": "bunx bnv pull --environment development",
"env:pull:preview": "bunx bnv pull --environment preview",
"env:pull:production": "bunx bnv pull --environment production",
"env:validate": "bunx bnv validate --environment development",
"env:validate:preview": "bun --env-file=.env.preview bunx bnv validate --environment preview",
"env:validate:production": "bunx bnv validate --environment production",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/package.json` around lines 6 - 11, Replace the hardcoded
./node_modules/better-env/dist/cli.js invocations in the npm scripts
(env:pull:development, env:pull:preview, env:pull:production, env:validate,
env:validate:preview, env:validate:production) with the published CLI command
bnv (i.e., use bnv <subcommand> or npx/bunx bnv for portability) so package
upgrades won’t break; also correct the env:validate:preview script to use
--environment preview instead of --environment production. Ensure each script
uses the bnv command and the preview script’s --environment flag matches its
name.

Comment on lines 68 to 78
function resolveOrigin() {
if (envConfig.server.vercelUrl) {
return `https://${envConfig.server.vercelUrl}`;
}

if (envConfig.server.origin) {
return envConfig.server.origin;
}

return `http://localhost:${envConfig.server.port}`;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

resolveOrigin() checks VERCEL_URL before ORIGIN, silently ignoring a configured custom domain in production.

VERCEL_URL is the domain name of the auto-generated deployment URL (e.g., *.vercel.app) and does not include the https:// scheme. It is set on every Vercel deployment — including production. It is not the custom domain but the unique deployment URL.

With the current priority, when ORIGIN is set to the canonical production domain (e.g., https://allthingsweb.dev), VERCEL_URL matches first and resolveOrigin() returns https://allthingsweb-abc123.vercel.app instead. The ORIGIN branch on line 73 is unreachable whenever Vercel is the host. This breaks any feature that relies on the canonical origin: email magic links, OAuth redirect URIs, OG image absolute URLs, etc.

The correct priority is ORIGIN > VERCEL_URL > localhost fallback.

🐛 Proposed fix — swap priority of ORIGIN and VERCEL_URL
 function resolveOrigin() {
+  if (envConfig.server.origin) {
+    return envConfig.server.origin;
+  }
+
   if (envConfig.server.vercelUrl) {
     return `https://${envConfig.server.vercelUrl}`;
   }
 
-  if (envConfig.server.origin) {
-    return envConfig.server.origin;
-  }
-
   return `http://localhost:${envConfig.server.port}`;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function resolveOrigin() {
if (envConfig.server.vercelUrl) {
return `https://${envConfig.server.vercelUrl}`;
}
if (envConfig.server.origin) {
return envConfig.server.origin;
}
return `http://localhost:${envConfig.server.port}`;
}
function resolveOrigin() {
if (envConfig.server.origin) {
return envConfig.server.origin;
}
if (envConfig.server.vercelUrl) {
return `https://${envConfig.server.vercelUrl}`;
}
return `http://localhost:${envConfig.server.port}`;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/lib/main/config.ts` around lines 68 - 78, resolveOrigin currently
checks envConfig.server.vercelUrl before envConfig.server.origin, causing ORIGIN
to be ignored on Vercel; change the logic in the resolveOrigin function to first
return envConfig.server.origin if present, then if not present return
`https://${envConfig.server.vercelUrl}` when envConfig.server.vercelUrl exists,
and finally fall back to `http://localhost:${envConfig.server.port}`; update the
branches that reference envConfig.server.origin, envConfig.server.vercelUrl, and
envConfig.server.port accordingly so ORIGIN takes precedence over VERCEL_URL.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🧹 Nitpick comments (6)
.agents/skills/og-image-generation/SKILL.md (1)

3-8: The front matter description and the body paragraph are identical — consider differentiating them.

Line 3 (description: field) and line 8 (first body sentence) carry exactly the same text. The front matter description is typically meant for machine/index consumption while the body can be richer (e.g., prerequisites, how it works, caveats). Keeping them identical adds no value for readers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/og-image-generation/SKILL.md around lines 3 - 8, The front
matter field `description:` and the first sentence of the body are duplicated;
change `description:` to a concise machine-readable summary (e.g., one-line
purpose) and rewrite the body opening sentence (the first paragraph under "# OG
Image Generation") to be richer—add prerequisites, how it works, or caveats—so
the front matter remains brief for indexing and the body provides human-facing
detail.
.agents/skills/base-app-setup/SKILL.md (1)

16-18: Consider adding -fL to curl commands for robustness.

All ten curl commands are missing --fail (-f) and --location (-L). Without -f, a non-2xx HTTP response is silently treated as success by the agent. Without -L, a redirect returns the redirect response instead of the recipe content.

🔧 Example fix (apply to all 10 curl commands)
-curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/nextjs-on-vercel
+curl -fL -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/nextjs-on-vercel

Also applies to: 24-26, 32-34, 40-42, 48-50, 56-58, 64-66, 72-74, 80-82, 88-90

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/base-app-setup/SKILL.md around lines 16 - 18, The curl
examples in SKILL.md (the lines showing commands like `curl -H "Accept:
text/markdown" https://fullstackrecipes.com/api/recipes/nextjs-on-vercel`) are
missing --fail and --location flags; update every occurrence of those curl
commands (all ten instances referenced in the comment) to include -fL (or
equivalently --fail --location) so that non-2xx responses cause failure and
redirects are followed, ensuring the agent receives the actual recipe content.
.agents/skills/better-env/references/cli.md (2)

9-11: ## Commands heading creates a flat structure — subcommands should be ###.

## Commands immediately precedes ## \better-env init`, making them siblings rather than a section and its entries. All individual command headings should be ###` so they nest under the Commands section.

📝 Proposed heading hierarchy fix
 ## Commands
 
-## `better-env init`
+### `better-env init`
 
 ...
 
-## `better-env pull`
+### `better-env pull`
 
 ...
 
-## `better-env add|upsert|update <key> <value>`
+### `better-env add|upsert|update <key> <value>`
 
 ...
 
-## `better-env delete <key>`
+### `better-env delete <key>`
 
 ...
 
-## `better-env load <file>`
+### `better-env load <file>`
 
 ...
 
-## `better-env validate`
+### `better-env validate`
 
 ...
 
-## `better-env environments list`
+### `better-env environments list`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/references/cli.md around lines 9 - 11, The
Markdown headings are flattened because "## Commands" and "## `better-env init`"
are at the same level; change all individual command headings (e.g., "##
`better-env init`") to subheadings ("### `better-env init`") so they nest under
the "## Commands" section and maintain a proper hierarchy.

84-92: Document the NODE_ENV=preview limitation and its workaround.

The PR notes that better-env@0.3.x cannot handle NODE_ENV=preview, so the env:validate:preview script passes --env-file=.env.preview combined with --environment production as a workaround. This is non-obvious behavior; a developer reading only this reference will be confused by the build:preview / env:validate:preview scripts in package.json.

📝 Suggested addition
 ## `better-env validate`
 
 Run env validation for `src/lib/*/config.ts` configs using Next.js env loading semantics.
 
 Example:
 
 ```bash
 better-env validate --environment development

+### Known limitation — NODE_ENV=preview
+
+better-env@0.3.x does not support NODE_ENV=preview. When validating a preview environment locally,
+pass the preview dotenv file via --env-file and use --environment production as a workaround:
+
+bash +bun --env-file=.env.preview node_modules/.bin/better-env validate --environment production +
+
+This matches the env:validate:preview script in package.json.

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/references/cli.md around lines 84 - 92, The
reference for the better-env validate command is missing documentation about
the known NODE_ENV=preview limitation; update
.agents/skills/better-env/references/cli.md to note that better-env@0.3.x
does not support NODE_ENV=preview and add the documented workaround used by
the repo: instruct users to pass the preview dotenv file with
--env-file=.env.preview and validate using --environment production (as done
by the env:validate:preview npm script) so readers understand the non-obvious
behavior of build:preview / env:validate:preview.


</details>

</blockquote></details>
<details>
<summary>.agents/skills/env-management/SKILL.md (1)</summary><blockquote>

`16-18`: **Document fallback strategy for external recipe endpoints.**

All three `fullstackrecipes.com` recipe endpoints are currently reachable. However, the cookbook's dependency on these external endpoints presents a risk: if any endpoint becomes unavailable or returns a non-200 response, agents will silently receive no instructions. Consider adding local inline documentation for each critical step as a fallback, or document a recovery procedure for endpoint failures.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.agents/skills/env-management/SKILL.md around lines 16 - 18, Document a
clear fallback strategy for the external recipe endpoints (e.g., the curl call
to https://fullstackrecipes.com/api/recipes/config-schema-setup and the other
fullstackrecipes.com recipe endpoints) by adding inline fallback instructions in
.agents/skills/env-management/SKILL.md: specify local step-by-step instructions
for each critical recipe, and/or a recovery procedure to follow when an endpoint
returns non-200 or is unreachable (include suggested retry logic, verification
steps, and a pointer to where offline copies of the recipes live). Ensure the
SKILL.md entries for each endpoint mention the exact endpoint path (like
/api/recipes/config-schema-setup), the expected response format, and the
fallback location or steps so agents have deterministic behavior when the
external service fails.


</details>

</blockquote></details>
<details>
<summary>.agents/skills/better-env/references/config-schema.md (1)</summary><blockquote>

`77-77`: **Clarify the `optional: true` + default caution.**

The current phrasing can be read as "never combine the two," but the intent is narrower: if you're relying on the Zod `.default()` to supply a fallback when the var is absent, adding `optional: true` is dangerous because the Zod parse step that applies the default may be skipped for `undefined` inputs. A reader who only wants the field to be non-required at the type level might miss that nuance.

Consider rewording to something like:

> If you want a fallback to apply when the env var is missing, do **not** mark the field `optional: true`; the optional flag may cause the Zod parse step (where the default is applied) to be skipped for `undefined` inputs.

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/references/config-schema.md at line 77, Rephrase
the caution so it clarifies the narrower intent: explain that combining
optional: true with Zod's .default() is problematic only when you rely on
.default() to provide a fallback for a missing env var, because the optional: true flag can cause the Zod parse step (where .default() is applied) to be
skipped for undefined inputs; update the text to the suggested wording (or
equivalent) that explicitly mentions optional: true, .default(), and the Zod
parse behavior so readers who only want a non-required type-level field don't
miss the nuance.


</details>

</blockquote></details>

</blockquote></details>

<details>
<summary>🤖 Prompt for all review comments with AI agents</summary>

Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/ai-agent-workflow/SKILL.md:

  • Around line 14-20: Update the prerequisite blurb under the "Type-Safe
    Environment Configuration" heading to reference the new parser: replace the Zod
    mention with better-env/config-schema and clarify that the recipe at
    config-schema-setup uses better-env's (Drizzle-like) schema API; specifically,
    edit the sentence that currently reads "using Zod with a Drizzle-like schema
    API" to something like "using better-env/config-schema (Drizzle-like schema
    API)" so the inline description matches the migration and the curl link target.

In @.agents/skills/authentication/SKILL.md:

  • Line 74: Replace occurrences of the compound noun phrases "sign in", "sign
    up", and the paired form "sign in/out" with their hyphenated forms "sign-in",
    "sign-up", and "sign-in/out" throughout the document (e.g., in headings,
    descriptions, and lists) to ensure consistent compound-noun styling; update all
    instances of those exact phrases so they read "sign-in", "sign-up", and
    "sign-in/out".

In @.agents/skills/better-env/agents/openai.yaml:

  • Around line 6-7: The policy currently sets allow_implicit_invocation: true
    which permits unconfirmed destructive operations for the better-env skill
    (affecting commands like delete and load --replace); change
    allow_implicit_invocation to false in the skill config to prevent silent
    invocation, and optionally add a comment or configuration note near the
    allow_implicit_invocation setting warning that destructive commands require
    explicit user confirmation or an explicit flag to run non-interactively to avoid
    accidental environment/secret deletion.

In @.agents/skills/better-env/references/cli.md:

  • Around line 30-36: The heading "## better-env add|upsert|update <key> <value>" and the following bullet list are inconsistent (title lists
    add|upsert|update while bullets describe add → update → upsert); update both the
    header and the bullet order to be consistent—preferably put upsert first since
    it's the default—so change the header to "## better-env upsert|add|update <key> <value>" (or reorder to add|update|upsert if you prefer) and reorder the
    bullets to match (e.g., upsert: set regardless…, add: fail if key exists,
    update: fail if key does not exist) ensuring both places use the same
    sequence.

In @.agents/skills/better-env/references/config.md:

  • Around line 37-40: The snippet defining the runtime object literal for
    gitignore uses a semicolon after the property (gitignore: { ensure: false; })
    which is invalid in a JavaScript/TypeScript value context; update the object
    literal(s) where gitignore and its property ensure are defined (both in the
    config.md snippet and the runtime.md snippet) to use a comma or no separator as
    appropriate (e.g., replace the trailing semicolon after ensure: false with a
    comma or remove it if last property) so the object literal is valid runtime
    syntax.

In @.agents/skills/better-env/references/env-validation.md:

  • Around line 22-28: Update the playbook section (the steps listing better-env
    pull/validate/upsert) to include a clear callout about the known
    better-env@0.3.x limitation with the preview environment: explain that using
    --environment preview (or NODE_ENV=preview) is non-standard and causes
    better-env validate to silently fail, and add a recommended workaround (e.g.,
    temporarily use a different environment name or set NODE_ENV to a supported
    value before running better-env validate, then pull/upsert as needed) so
    developers running better-env validate, better-env pull, and better-env upsert
    for preview know to apply the workaround.

In @.agents/skills/better-env/references/runtime.md:

  • Around line 33-35: The fragment defining the gitignore object uses an invalid
    semicolon in the object literal ("gitignore: { ensure: false; }"); update the
    "gitignore" value to a valid JavaScript/TypeScript object by removing the
    semicolon so the "ensure" property is expressed as ensure: false (e.g.,
    gitignore: { ensure: false } ), matching the same fix applied in config.md and
    preserving the surrounding markdown content in runtime.md.

In @.agents/skills/better-env/SKILL.md:

  • Line 3: The description claims Fly.io support but the runtime config example
    only shows vercelAdapter, netlifyAdapter, railwayAdapter, and cloudflareAdapter
    (no flyAdapter) in SKILL.md; either remove "Fly.io" from the description line or
    add a matching flyAdapter entry to the runtime config example and any related
    documentation snippets. Update the SKILL.md content so the description and the
    runtime config example are consistent: if adding support, include the flyAdapter
    symbol in the example and mention any required initialization in the runtime
    config section; if removing support, delete "Fly.io" from the description to
    avoid misleading users.
  • Line 3: Update the SKILL.md description to remove the unsupported provider
    "Fly.io": edit the description string that currently lists "Vercel, Netlify,
    Railway, Cloudflare, and Fly.io" and remove "Fly.io" (and any mention of a
    flyAdapter) so it only references the actual supported providers (Vercel,
    Netlify, Railway, and Cloudflare). Ensure the sentence remains grammatically
    correct after removal.

In @.agents/skills/env-management/SKILL.md:

  • Line 14: In the SKILL.md description replace the inaccurate mention of "Zod"
    with "better-env/config-schema" so the first recipe description reads e.g.
    "Type-safe environment variable validation using better-env/config-schema with a
    Drizzle-like schema API" instead of "Zod"; update the exact phrase "Type-safe
    environment variable validation using Zod with a Drizzle-like schema API" to
    reference better-env/config-schema so agents consume the correct schema library.

In @.agents/skills/og-image-generation/SKILL.md:

  • Around line 10-12: The curl example in SKILL.md uses Accept: text/markdown but
    the /api/recipes/og-image-generation endpoint returns application/json with a
    content field containing the Markdown; update the example to request JSON (e.g.,
    Accept: application/json) and show how to extract the Markdown from the JSON
    response (e.g., instruct to parse the response and use the content property or
    pipe through jq to get .content) so the documented example matches the actual
    API behavior and returns the recipe Markdown.

In @.agents/skills/ralph-loop/SKILL.md:

  • Around line 18-20: Update every curl example that currently uses -H "Accept: text/markdown" to include the --fail (or -f) flag and change the header to
    -H "Accept: text/plain"; specifically replace occurrences of the curl snippet
    curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/agent-setup (and the other similar
    snippets on the same file) so they read with --fail/-f and Accept: text/plain, ensuring failed HTTP 4xx/5xx responses return nonzero exit codes
    and the header matches the documented endpoint pattern.

In @.agents/skills/testing/SKILL.md:

  • Line 16: Update the stale phrase "using Zod" in the SKILL.md description to
    reference the new parser package "better-env" (specifically
    "better-env/config-schema") so the sentence "Type-safe environment variable
    validation using Zod with a Drizzle-like schema API..." becomes "Type-safe
    environment variable validation using better-env/config-schema with a
    Drizzle-like schema API..."; search for the exact phrase "using Zod" and replace
    it with "using better-env/config-schema" and ensure any other mentions of "Zod"
    in that document are similarly updated to avoid confusion.

Nitpick comments:
In @.agents/skills/base-app-setup/SKILL.md:

  • Around line 16-18: The curl examples in SKILL.md (the lines showing commands
    like curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/nextjs-on-vercel) are missing --fail
    and --location flags; update every occurrence of those curl commands (all ten
    instances referenced in the comment) to include -fL (or equivalently --fail
    --location) so that non-2xx responses cause failure and redirects are followed,
    ensuring the agent receives the actual recipe content.

In @.agents/skills/better-env/references/cli.md:

  • Around line 9-11: The Markdown headings are flattened because "## Commands"
    and "## better-env init" are at the same level; change all individual command
    headings (e.g., "## better-env init") to subheadings ("### better-env init")
    so they nest under the "## Commands" section and maintain a proper hierarchy.
  • Around line 84-92: The reference for the better-env validate command is
    missing documentation about the known NODE_ENV=preview limitation; update
    .agents/skills/better-env/references/cli.md to note that better-env@0.3.x
    does not support NODE_ENV=preview and add the documented workaround used by
    the repo: instruct users to pass the preview dotenv file with
    --env-file=.env.preview and validate using --environment production (as done
    by the env:validate:preview npm script) so readers understand the non-obvious
    behavior of build:preview / env:validate:preview.

In @.agents/skills/better-env/references/config-schema.md:

  • Line 77: Rephrase the caution so it clarifies the narrower intent: explain
    that combining optional: true with Zod's .default() is problematic only when
    you rely on .default() to provide a fallback for a missing env var, because
    the optional: true flag can cause the Zod parse step (where .default() is
    applied) to be skipped for undefined inputs; update the text to the suggested
    wording (or equivalent) that explicitly mentions optional: true, .default(),
    and the Zod parse behavior so readers who only want a non-required type-level
    field don't miss the nuance.

In @.agents/skills/env-management/SKILL.md:

  • Around line 16-18: Document a clear fallback strategy for the external recipe
    endpoints (e.g., the curl call to
    https://fullstackrecipes.com/api/recipes/config-schema-setup and the other
    fullstackrecipes.com recipe endpoints) by adding inline fallback instructions in
    .agents/skills/env-management/SKILL.md: specify local step-by-step instructions
    for each critical recipe, and/or a recovery procedure to follow when an endpoint
    returns non-200 or is unreachable (include suggested retry logic, verification
    steps, and a pointer to where offline copies of the recipes live). Ensure the
    SKILL.md entries for each endpoint mention the exact endpoint path (like
    /api/recipes/config-schema-setup), the expected response format, and the
    fallback location or steps so agents have deterministic behavior when the
    external service fails.

In @.agents/skills/og-image-generation/SKILL.md:

  • Around line 3-8: The front matter field description: and the first sentence
    of the body are duplicated; change description: to a concise machine-readable
    summary (e.g., one-line purpose) and rewrite the body opening sentence (the
    first paragraph under "# OG Image Generation") to be richer—add prerequisites,
    how it works, or caveats—so the front matter remains brief for indexing and the
    body provides human-facing detail.

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

Comment on lines +14 to +20
### Type-Safe Environment Configuration

Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.

```bash
curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/config-schema-setup
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Prerequisite description still references Zod — update to reflect better-env migration.

Line 16 describes this prerequisite as "using Zod with a Drizzle-like schema API", but the entire purpose of this PR is to replace the Zod-based env parser with better-env/config-schema. The "Drizzle-like schema API" description is characteristic of better-env, not Zod. If config-schema-setup is meant to point to the better-env recipe, the inline blurb is misleading for any AI agent consuming this skill.

📝 Suggested correction
-Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
+Type-safe environment variable validation using better-env with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/ai-agent-workflow/SKILL.md around lines 14 - 20, Update the
prerequisite blurb under the "Type-Safe Environment Configuration" heading to
reference the new parser: replace the Zod mention with better-env/config-schema
and clarify that the recipe at `config-schema-setup` uses better-env's
(Drizzle-like) schema API; specifically, edit the sentence that currently reads
"using Zod with a Drizzle-like schema API" to something like "using
better-env/config-schema (Drizzle-like schema API)" so the inline description
matches the migration and the curl link target.


### Better Auth Components

Add UI components and pages for authentication flows including sign in, sign up, forgot password, reset password, and email verification.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Minor: hyphenate sign-in, sign-up, and sign-in/out as compound nouns.

✏️ Proposed fix
-Add UI components and pages for authentication flows including sign in, sign up, forgot password, reset password, and email verification.
+Add UI components and pages for authentication flows including sign-in, sign-up, forgot password, reset password, and email verification.
-Use Better Auth for client and server-side authentication. Covers session access, protected routes, sign in/out, and fetching user data.
+Use Better Auth for client and server-side authentication. Covers session access, protected routes, sign-in/out, and fetching user data.

Also applies to: 98-98

🧰 Tools
🪛 LanguageTool

[grammar] ~74-~74: Use a hyphen to join words.
Context: ... for authentication flows including sign in, sign up, forgot password, reset pass...

(QB_NEW_EN_HYPHEN)


[grammar] ~74-~74: Use a hyphen to join words.
Context: ...entication flows including sign in, sign up, forgot password, reset password, and...

(QB_NEW_EN_HYPHEN)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/authentication/SKILL.md at line 74, Replace occurrences of
the compound noun phrases "sign in", "sign up", and the paired form "sign
in/out" with their hyphenated forms "sign-in", "sign-up", and "sign-in/out"
throughout the document (e.g., in headings, descriptions, and lists) to ensure
consistent compound-noun styling; update all instances of those exact phrases so
they read "sign-in", "sign-up", and "sign-in/out".

Comment on lines +6 to +7
policy:
allow_implicit_invocation: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, explore the better-env skill directory structure
fd -type f . .agents/skills/better-env/ | head -30

Repository: allthingsweb-dev/allthingsweb

Length of output: 243


🏁 Script executed:

# Check for SKILL.md or similar documentation
find .agents/skills/better-env/ -maxdepth 3 -type f \( -name "*.md" -o -name "SKILL*" -o -name "README*" \)

Repository: allthingsweb-dev/allthingsweb

Length of output: 410


🏁 Script executed:

# Look at the openai.yaml file content to understand the full context
cat .agents/skills/better-env/agents/openai.yaml

Repository: allthingsweb-dev/allthingsweb

Length of output: 355


🏁 Script executed:

# Search for confirmation, policy, or permission-related keywords in the skill tree
fd -e yaml -e md . .agents/skills/better-env/ --exec grep -l -i 'confirm\|allow_implicit\|policy\|permission\|require.*approval\|destructive' {}

Repository: allthingsweb-dev/allthingsweb

Length of output: 172


🏁 Script executed:

# Check the parent skill configuration or documentation
find .agents/skills/better-env/ -maxdepth 2 -type f -name "*.md" -exec cat {} \;

Repository: allthingsweb-dev/allthingsweb

Length of output: 12525


allow_implicit_invocation: true enables unconfirmed destructive operations on remote environments.

This skill provides delete and load --replace commands that can silently remove environment variables (including secrets). The SKILL.md documentation confirms that prompts exist only for init ("skip prompts (only used by init today)"), with no confirmation step documented for delete, update, or load --replace operations. The CLI is intentionally designed for automation workflows, making destructive operations non-interactive by default.

Setting allow_implicit_invocation: true combined with this design creates risk of unintended env var deletion. Change to allow_implicit_invocation: false unless the framework enforces explicit user confirmation at invocation time.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/agents/openai.yaml around lines 6 - 7, The policy
currently sets allow_implicit_invocation: true which permits unconfirmed
destructive operations for the better-env skill (affecting commands like delete
and load --replace); change allow_implicit_invocation to false in the skill
config to prevent silent invocation, and optionally add a comment or
configuration note near the allow_implicit_invocation setting warning that
destructive commands require explicit user confirmation or an explicit flag to
run non-interactively to avoid accidental environment/secret deletion.

Comment on lines +30 to +36
## `better-env add|upsert|update <key> <value>`

Create/change a single remote env var:

- `add`: fail if key exists
- `update`: fail if key does not exist
- `upsert` (default style): set regardless of existence
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

add|upsert|update title order doesn't match the description order.

The command title lists add|upsert|update, but the description enumerates add → update → upsert. Since upsert is the default style it's the most important variant; consider putting it first in both the title and the description, or at least making the two orders consistent.

📝 Proposed fix
-## `better-env add|upsert|update <key> <value>`
+## `better-env upsert|add|update <key> <value>`
 
 Create/change a single remote env var:
 
+- `upsert` (default style): set regardless of existence
 - `add`: fail if key exists
 - `update`: fail if key does not exist
-- `upsert` (default style): set regardless of existence
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## `better-env add|upsert|update <key> <value>`
Create/change a single remote env var:
- `add`: fail if key exists
- `update`: fail if key does not exist
- `upsert` (default style): set regardless of existence
## `better-env upsert|add|update <key> <value>`
Create/change a single remote env var:
- `upsert` (default style): set regardless of existence
- `add`: fail if key exists
- `update`: fail if key does not exist
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/references/cli.md around lines 30 - 36, The
heading "## `better-env add|upsert|update <key> <value>`" and the following
bullet list are inconsistent (title lists add|upsert|update while bullets
describe add → update → upsert); update both the header and the bullet order to
be consistent—preferably put `upsert` first since it's the default—so change the
header to "## `better-env upsert|add|update <key> <value>`" (or reorder to
`add|update|upsert` if you prefer) and reorder the bullets to match (e.g.,
`upsert`: set regardless…, `add`: fail if key exists, `update`: fail if key does
not exist) ensuring both places use the same sequence.

Comment on lines +37 to +40
gitignore: {
ensure: false;
}
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Invalid TypeScript syntax in code snippet — semicolon instead of comma.

The object literal fragment uses a semicolon as the property separator, which is a syntax error in a JavaScript/TypeScript value context:

gitignore: {
  ensure: false;  // ← SyntaxError in a value object literal
}

Semicolons are valid separators only in TypeScript type/interface definitions, not in runtime object literals. The same mistake appears in runtime.md (lines 33–35). The fix in both places is:

✏️ Proposed fix
 gitignore: {
-  ensure: false;
+  ensure: false,
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/references/config.md around lines 37 - 40, The
snippet defining the runtime object literal for gitignore uses a semicolon after
the property (gitignore: { ensure: false; }) which is invalid in a
JavaScript/TypeScript value context; update the object literal(s) where
gitignore and its property ensure are defined (both in the config.md snippet and
the runtime.md snippet) to use a comma or no separator as appropriate (e.g.,
replace the trailing semicolon after ensure: false with a comma or remove it if
last property) so the object literal is valid runtime syntax.

@@ -0,0 +1,69 @@
---
name: better-env
description: Better environment variable management for agents and humans with full type safety, CLI-based remote environment synchronization, and environment validation. Use when setting up typed config schemas, validating env variables, or managing remote env vars across Vercel, Netlify, Railway, Cloudflare, and Fly.io with better-env.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n .agents/skills/better-env/SKILL.md

Repository: allthingsweb-dev/allthingsweb

Length of output: 3543


🏁 Script executed:

rg -i "fly" --type md --type ts --type js -A 2 -B 2

Repository: allthingsweb-dev/allthingsweb

Length of output: 1655


🏁 Script executed:

find . -name "*fly*" -o -name "*Fly*" | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

ls -la .agents/skills/better-env/references/ 2>/dev/null || find . -path "*better-env*references*" -type f

Repository: allthingsweb-dev/allthingsweb

Length of output: 559


🏁 Script executed:

find . -path "*better-env*" -type f | head -20

Repository: allthingsweb-dev/allthingsweb

Length of output: 491


🏁 Script executed:

rg "flyAdapter|Fly\.io" -i

Repository: allthingsweb-dev/allthingsweb

Length of output: 55


🏁 Script executed:

rg "cloudflareAdapter|vercelAdapter" -A 5 | head -40

Repository: allthingsweb-dev/allthingsweb

Length of output: 629


Remove Fly.io from the description or add flyAdapter to the runtime config example.

Line 3 advertises Fly.io as a supported provider, but line 40 lists only vercelAdapter, netlifyAdapter, railwayAdapter, and cloudflareAdapter. No flyAdapter reference or documentation exists in the repository. Either add flyAdapter to line 40 if better-env supports it, or remove Fly.io from the description.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/SKILL.md at line 3, The description claims Fly.io
support but the runtime config example only shows vercelAdapter, netlifyAdapter,
railwayAdapter, and cloudflareAdapter (no flyAdapter) in SKILL.md; either remove
"Fly.io" from the description line or add a matching flyAdapter entry to the
runtime config example and any related documentation snippets. Update the
SKILL.md content so the description and the runtime config example are
consistent: if adding support, include the flyAdapter symbol in the example and
mention any required initialization in the runtime config section; if removing
support, delete "Fly.io" from the description to avoid misleading users.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

better-env npm package flyAdapter Fly.io support

💡 Result:

I couldn’t find any evidence (docs, README, repo, or issues) that the better-env npm package (currently shown as v0.0.1) includes a flyAdapter or any documented Fly.io-specific support. The only public listing I could locate just identifies it as “CLI for better-env,” without adapter/platform details. [1]

If your real goal is Fly.io support for Better Auth’s BETTER_AUTH_URL, Fly’s standard approach is to set env vars via either:

  • [env] in fly.toml for non-secrets [2], and/or
  • fly secrets set ... for secrets (Fly docs recommend secrets instead of relying on .env files in production) [3]

And Better Auth expects BETTER_AUTH_URL to be set to your app’s base URL (your Fly domain) in production. [4]

Sources:
[1] better-env listing (Libraries.io) (libraries.io)
[2] Fly.io fly.toml env section (fly.io)
[3] Fly.io guidance on secrets vs .env (community.fly.io)
[4] Better Auth install docs (BETTER_AUTH_URL) (better-auth.com)

Citations:


🏁 Script executed:

# Read the SKILL.md file to see the actual content
cat -n .agents/skills/better-env/SKILL.md

Repository: allthingsweb-dev/allthingsweb

Length of output: 3543


Remove Fly.io from the description—it is not supported by the better-env package.

Line 3 advertises Fly.io support, but better-env does not export a flyAdapter. Remove Fly.io from the description to reflect the actual supported providers (Vercel, Netlify, Railway, and Cloudflare only).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/better-env/SKILL.md at line 3, Update the SKILL.md
description to remove the unsupported provider "Fly.io": edit the description
string that currently lists "Vercel, Netlify, Railway, Cloudflare, and Fly.io"
and remove "Fly.io" (and any mention of a `flyAdapter`) so it only references
the actual supported providers (Vercel, Netlify, Railway, and Cloudflare).
Ensure the sentence remains grammatically correct after removal.


### Type-Safe Environment Configuration

Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inaccurate library attribution — replace "Zod" with better-env/config-schema.

Line 14 describes the first recipe as using "Zod with a Drizzle-like schema API," but this PR explicitly replaces the Zod-only parser with better-env/config-schema. Since this skill file is consumed by AI agents to guide implementation, describing the schema layer as Zod will cause those agents to reach for Zod instead of better-env/config-schema.

📝 Proposed fix
-Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
+Type-safe environment variable validation using better-env's Drizzle-like config-schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/env-management/SKILL.md at line 14, In the SKILL.md
description replace the inaccurate mention of "Zod" with
"better-env/config-schema" so the first recipe description reads e.g. "Type-safe
environment variable validation using better-env/config-schema with a
Drizzle-like schema API" instead of "Zod"; update the exact phrase "Type-safe
environment variable validation using Zod with a Drizzle-like schema API" to
reference better-env/config-schema so agents consume the correct schema library.

Comment on lines +10 to +12
```bash
curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/og-image-generation
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

https://fullstackrecipes.com/api/recipes/og-image-generation accessibility status content

💡 Result:

  • Accessibility/status: The endpoint is publicly accessible and responds with JSON (Content-Type: application/json). [1]
  • Returned content: The JSON payload contains a content field with a Markdown recipe titled “OG Image Generation” describing how to generate dynamic Open Graph images in Next.js using next/og / ImageResponse, including:
    • suggested file structure (opengraph-image.tsx at root and per dynamic route),
    • setup examples for static and dynamic OG images,
    • exporting alt, size (1200×630), and contentType (noting alt for accessibility),
    • notes on Satori/JSX styling constraints and testing routes locally,
    • reference links to Next.js/Vercel/Satori docs. [1]

Source(s): [1]


Update the curl example to reflect the actual endpoint response format.

The endpoint is accessible but returns JSON (not Markdown). The curl example specifies Accept: text/markdown, but the endpoint responds with application/json containing a content field with the Markdown recipe. Adjust the example to match the actual API behavior, or parse the JSON response appropriately.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/og-image-generation/SKILL.md around lines 10 - 12, The curl
example in SKILL.md uses Accept: text/markdown but the
/api/recipes/og-image-generation endpoint returns application/json with a
content field containing the Markdown; update the example to request JSON (e.g.,
Accept: application/json) and show how to extract the Markdown from the JSON
response (e.g., instruct to parse the response and use the content property or
pipe through jq to get .content) so the documented example matches the actual
API behavior and returns the recipe Markdown.

Comment on lines +18 to +20
```bash
curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/agent-setup
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n .agents/skills/ralph-loop/SKILL.md

Repository: allthingsweb-dev/allthingsweb

Length of output: 2109


🌐 Web query:

fullstackrecipes.com api recipes agent-setup

💡 Result:

To pull the agent-setup recipe from fullstackrecipes.com (via the “API recipes” endpoint), you generally have two options:

1) Use the MCP server (recommended)

Add the FullstackRecipes MCP server to your agent tooling:

bunx add-mcp https://fullstackrecipes.com/api/mcp

Then reference the recipe by URI (pattern used by their skills/recipes): recipe://fullstackrecipes.com/agent-setup. [1][2]

2) Fetch the recipe directly over HTTP

Recipes can be fetched as plain text markdown via:

curl -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/agent-setup

(This endpoint/Accept: text/plain pattern is how FullstackRecipes documents direct recipe fetching.) [2]

Install the agent-setup skill (separate from fetching the recipe text)

pnpm dlx add-skill https://github.com/andrelandgraf/fullstackrecipes/agent-setup

[3]

Sources: [1] [2] [3]


🌐 Web query:

fullstackrecipes.com api recipes user-stories-setup

💡 Result:

fullstackrecipes.com exposes the user-stories-setup recipe at:

  • API endpoint: https://fullstackrecipes.com/api/recipes/user-stories-setup (returns JSON with a content field containing the markdown recipe). [1]
  • Direct fetch (as plain text):
    curl -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/user-stories-setup
    (This curl form is referenced by the skill listing.) [2]

What the recipe sets up (high level):

  • Create docs/user-stories/ to store user story JSON files. [1]
  • Add scripts/verify-user-stories.ts (Bun + Zod) to validate that each *.json file in docs/user-stories/ is an array of objects like:
    • description: string
    • steps: string[]
    • passes: boolean [1]
  • Add a package.json script, e.g. user-stories:verify, to run the verifier. [1]

Sources: [1] [2]


🌐 Web query:

fullstackrecipes.com api recipes ralph-setup

💡 Result:

The Fullstack Recipes “ralph-setup” recipe is available via their Recipe API endpoint:

  • Endpoint: https://fullstackrecipes.com/api/recipes/ralph-setup (returns JSON with a content field containing the full Markdown recipe) [1]
  • Fetch (as plain text/markdown):
    curl -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/ralph-setup
    (This curl pattern is referenced by the ralph-setup skill docs.) [2]

The recipe content includes:

  • Install via shadcn registry: bunx --bun shadcn@latest add https://fullstackrecipes.com/r/ralph.json [1]
  • A scripts/ralph/runner.ts Bun script and scripts/ralph/prompt.md + scripts/ralph/log.md templates
  • A package.json script ("ralph": "bun run scripts/ralph/runner.ts") and a note to install Claude Code CLI (npm install -g @anthropic-ai/claude-code``) [1]

Sources: [1], [2]


Add --fail (-f) flag and use Accept: text/plain header in all curl commands.

Without -f, HTTP 4xx/5xx responses exit with code 0 and print the error body as markdown, misleading the user. Additionally, the documented endpoint pattern uses Accept: text/plain, not text/markdown.

📄 Proposed fixes
-curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/agent-setup
+curl -f -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/agent-setup
-curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/user-stories-setup
+curl -f -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/user-stories-setup
-curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/using-user-stories
+curl -f -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/using-user-stories
-curl -H "Accept: text/markdown" https://fullstackrecipes.com/api/recipes/ralph-setup
+curl -f -H "Accept: text/plain" https://fullstackrecipes.com/api/recipes/ralph-setup

Also applies to: lines 28-30, 36-38, 44-46

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/ralph-loop/SKILL.md around lines 18 - 20, Update every curl
example that currently uses `-H "Accept: text/markdown"` to include the `--fail`
(or `-f`) flag and change the header to `-H "Accept: text/plain"`; specifically
replace occurrences of the curl snippet `curl -H "Accept: text/markdown"
https://fullstackrecipes.com/api/recipes/agent-setup` (and the other similar
snippets on the same file) so they read with `--fail`/`-f` and `Accept:
text/plain`, ensuring failed HTTP 4xx/5xx responses return nonzero exit codes
and the header matches the documented endpoint pattern.


### Type-Safe Environment Configuration

Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

"using Zod" is stale — update to reference better-env.

This PR replaces the Zod-only env parser with better-env/config-schema. The phrase "using Zod" is misleading for anyone consuming this skill going forward.

✏️ Suggested wording update
-Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
+Type-safe environment variable validation using better-env with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Type-safe environment variable validation using Zod with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
Type-safe environment variable validation using better-env with a Drizzle-like schema API. Supports server/public fields, feature flags, either-or constraints, and client-side protection.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/testing/SKILL.md at line 16, Update the stale phrase "using
Zod" in the SKILL.md description to reference the new parser package
"better-env" (specifically "better-env/config-schema") so the sentence
"Type-safe environment variable validation using Zod with a Drizzle-like schema
API..." becomes "Type-safe environment variable validation using
better-env/config-schema with a Drizzle-like schema API..."; search for the
exact phrase "using Zod" and replace it with "using better-env/config-schema"
and ensure any other mentions of "Zod" in that document are similarly updated to
avoid confusion.

@andrelandgraf andrelandgraf merged commit 27b0bd0 into main Feb 21, 2026
4 checks passed
@andrelandgraf andrelandgraf deleted the codex/better-env-migration branch February 21, 2026 23:53
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.

1 participant