{"_id":"@amadeni/dev-contract","_rev":"4-88ab3ad3dceaec628aef3a7f38ab8902","name":"@amadeni/dev-contract","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@amadeni/dev-contract","version":"0.1.0","keywords":["convex","nextjs","dev-environment","better-auth","cli","automation"],"author":{"name":"Amadeni","email":"nicolai.hallberg@amadeni.ai"},"license":"MIT","_id":"@amadeni/dev-contract@0.1.0","maintainers":[{"name":"amadeni_ai","email":"admin@amadeni.ai"}],"homepage":"https://github.com/amadeni/dev-contract#readme","bugs":{"url":"https://github.com/amadeni/dev-contract/issues"},"bin":{"dev-contract":"dist/cli.js"},"dist":{"shasum":"ef0c284edd2c0fc04adfd7e067fc4abc7df4ee21","tarball":"https://registry.npmjs.org/@amadeni/dev-contract/-/dev-contract-0.1.0.tgz","fileCount":34,"integrity":"sha512-UtHDrxfZ8MVzAPmM/zoJmfH7yyluxF7PmACYFbEfR+uOXCflskp0LGuQXrn8gGuGio0+1/NntM3XCifmYGFxog==","signatures":[{"sig":"MEUCIGK8YEDKXWI8alU4/zEW3NxvHc7xtqjuwTGcA4Px144vAiEA9oGUCeUp81FaUx4dW38Hc9Eqfvio5dkHB5xtD26w1Fs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":77913},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"b41c44da060521d6d56a35f8cd64283fe04f0965","scripts":{"ci":"pnpm run prettier:check && pnpm run lint && pnpm run ts && pnpm run check-spelling && pnpm run test","ts":"tsc --noEmit --incremental false","lint":"eslint src/","test":"vitest run","build":"tsc","prepare":"tsc","release":"pnpm version patch && git push && git push --tags","release:major":"pnpm version major && git push && git push --tags","release:minor":"pnpm version minor && git push && git push --tags","check-spelling":"cspell '**/*.*' --no-progress","prepublishOnly":"pnpm run build","prettier:check":"prettier --check .","prettier:write":"prettier --write ."},"_npmUser":{"name":"amadeni_ai","email":"admin@amadeni.ai"},"repository":{"url":"git+https://github.com/amadeni/dev-contract.git","type":"git"},"_npmVersion":"10.9.8","description":"Standardized dev-start/dev-auth process contract for the Amadeni project fleet: ready means a verified login","directories":{},"sideEffects":false,"_nodeVersion":"22.22.3","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6","devDependencies":{"cspell":"^9.7.0","eslint":"^10.0.2","vitest":"^4.0.18","prettier":"^3.8.1","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^25.3.3","typescript-eslint":"^8.56.1"},"_npmOperationalInternal":{"tmp":"tmp/dev-contract_0.1.0_1786556823721_0.7185361937653798","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@amadeni/dev-contract","version":"0.1.1","keywords":["convex","nextjs","dev-environment","better-auth","cli","automation"],"author":{"name":"Amadeni","email":"nicolai.hallberg@amadeni.ai"},"license":"MIT","_id":"@amadeni/dev-contract@0.1.1","maintainers":[{"name":"amadeni_ai","email":"admin@amadeni.ai"}],"homepage":"https://github.com/amadeni/dev-contract#readme","bugs":{"url":"https://github.com/amadeni/dev-contract/issues"},"bin":{"dev-contract":"dist/cli.js"},"dist":{"shasum":"b43518212459b668d3d3a1fc7ad699bea1bb016a","tarball":"https://registry.npmjs.org/@amadeni/dev-contract/-/dev-contract-0.1.1.tgz","fileCount":34,"integrity":"sha512-JPYm+FrRp5+RNKBlWY8UqqY0dqEZNM/WUptbRBhS00odJvv3CjAp7ddVzOu6FvW9beUtW2iVY+8uLYZpR0lgtg==","signatures":[{"sig":"MEUCIQCHZRsPmMQ9Fp4H3zLNqVkUsDEZ6zdZQj+oCvvCGv9TngIgIU4waGavZkkxjbrb5+Hs76K9dSEFg4dZYFQY+EHIWT4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amadeni%2fdev-contract@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":77913},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"43d5487f6588027567bfd333735ae1bc6fd2c890","scripts":{"ci":"pnpm run prettier:check && pnpm run lint && pnpm run ts && pnpm run check-spelling && pnpm run test","ts":"tsc --noEmit --incremental false","lint":"eslint src/","test":"vitest run","build":"tsc","prepare":"tsc","release":"pnpm version patch && git push && git push --tags","release:major":"pnpm version major && git push && git push --tags","release:minor":"pnpm version minor && git push && git push --tags","check-spelling":"cspell '**/*.*' --no-progress","prepublishOnly":"pnpm run build","prettier:check":"prettier --check .","prettier:write":"prettier --write ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:fdd00c67-35fc-475e-baab-ef3eecdc27fc"}},"repository":{"url":"git+https://github.com/amadeni/dev-contract.git","type":"git"},"_npmVersion":"12.0.2","description":"Standardized dev-start/dev-auth process contract for the Amadeni project fleet: ready means a verified login","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6","devDependencies":{"cspell":"^9.7.0","eslint":"^10.0.2","vitest":"^4.0.18","prettier":"^3.8.1","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^25.3.3","typescript-eslint":"^8.56.1"},"_npmOperationalInternal":{"tmp":"tmp/dev-contract_0.1.1_1786573514735_0.9301842436413645","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@amadeni/dev-contract","version":"0.1.2","keywords":["convex","nextjs","dev-environment","better-auth","cli","automation"],"author":{"name":"Amadeni","email":"nicolai.hallberg@amadeni.ai"},"license":"MIT","_id":"@amadeni/dev-contract@0.1.2","maintainers":[{"name":"amadeni_ai","email":"admin@amadeni.ai"}],"homepage":"https://github.com/amadeni/dev-contract#readme","bugs":{"url":"https://github.com/amadeni/dev-contract/issues"},"bin":{"dev-contract":"dist/cli.js"},"dist":{"shasum":"88f7d427507268fd0b0a3bc5f7d35395f1f5238a","tarball":"https://registry.npmjs.org/@amadeni/dev-contract/-/dev-contract-0.1.2.tgz","fileCount":34,"integrity":"sha512-2m68KPRvYSGhS2gum0bSauvG17NPipIxJNI58qDk2OSf59Qk+FPapnF6FPhFj3neKWqLF9Kiod6Edo5DTUOUiA==","signatures":[{"sig":"MEQCIH+f4ynOn3bEHZPLA5UqOtC06OYh39QsovC8HeXPCZVoAiBwFJWQsoyjLT7XC3VAQyfmCjLYdqXtDRifyDMVOIfhSw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCICyTonQHkCdY6EdKn3ZdSXGuHn0FcQOukO31v+ZlHtVGAiEAkdR6FJefiPIjm2tAnj31Ru2CAGoNXWTcySIGWY6nxeI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amadeni%2fdev-contract@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":80274},"main":"dist/index.js","type":"module","types":"dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"4dbbe061392fffa585d2aec7cf3a0a2a03124830","scripts":{"ci":"pnpm run prettier:check && pnpm run lint && pnpm run ts && pnpm run check-spelling && pnpm run test","ts":"tsc --noEmit --incremental false","lint":"eslint src/","test":"vitest run","build":"tsc","prepare":"tsc","release":"pnpm version patch && git push && git push --tags","release:major":"pnpm version major && git push && git push --tags","release:minor":"pnpm version minor && git push && git push --tags","check-spelling":"cspell '**/*.*' --no-progress","prepublishOnly":"pnpm run build","prettier:check":"prettier --check .","prettier:write":"prettier --write ."},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:fdd00c67-35fc-475e-baab-ef3eecdc27fc"}},"repository":{"url":"git+https://github.com/amadeni/dev-contract.git","type":"git"},"_npmVersion":"12.0.2","description":"Standardized dev-start/dev-auth process contract for the Amadeni project fleet: ready means a verified login","directories":{},"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6","devDependencies":{"cspell":"^9.7.0","eslint":"^10.0.2","vitest":"^4.0.18","prettier":"^3.8.1","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^25.3.3","typescript-eslint":"^8.56.1"},"_npmOperationalInternal":{"tmp":"tmp/dev-contract_0.1.2_1789383998675_0.21903236443699892","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"_id":"@amadeni/dev-contract@0.2.0","bin":{"dev-contract":"dist/cli.js"},"bugs":{"url":"https://github.com/amadeni/dev-contract/issues"},"dist":{"shasum":"1703b963d16cbe597b3784ada441884b6a01e936","tarball":"https://registry.npmjs.org/@amadeni/dev-contract/-/dev-contract-0.2.0.tgz","fileCount":34,"integrity":"sha512-picgf2C3UXcf1SW2YHOGtTr8aH2XoXywOHsGQEbxwlqTsle3luq9nHlHHdNBo3PoRldAdJGy2Vr/1XlK3L9j9g==","signatures":[{"sig":"MEQCIFwgCNcCJvdish+JIzxSwhlet0krvi6puZvtVL33uuaJAiBXt0QO/X8QDMuamOeW1//4U5ZnR6h1cxR5GheRf2Z3KQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDbFekkC9x1auQYJtUk+skKpoDr6MCClk/15JBVz1om6AiAEhzmcJOS3pHFDgwO6V8Pa1ipRZchPHe3mjPXoE3xqew=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@amadeni%2fdev-contract@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":89065},"main":"dist/index.js","name":"@amadeni/dev-contract","type":"module","types":"dist/index.d.ts","author":{"name":"Amadeni","email":"nicolai.hallberg@amadeni.ai"},"engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"089726a8f7ef430915d3acd7b6819974b346b84a","license":"MIT","scripts":{"ci":"pnpm run prettier:check && pnpm run lint && pnpm run ts && pnpm run check-spelling && pnpm run test","ts":"tsc --noEmit --incremental false","lint":"eslint src/","test":"vitest run","build":"tsc","prepare":"tsc","release":"pnpm version patch && git push && git push --tags","release:major":"pnpm version major && git push && git push --tags","release:minor":"pnpm version minor && git push && git push --tags","check-spelling":"cspell '**/*.*' --no-progress","prepublishOnly":"pnpm run build","prettier:check":"prettier --check .","prettier:write":"prettier --write ."},"version":"0.2.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:fdd00c67-35fc-475e-baab-ef3eecdc27fc"}},"homepage":"https://github.com/amadeni/dev-contract#readme","keywords":["convex","nextjs","dev-environment","better-auth","cli","automation"],"repository":{"url":"git+https://github.com/amadeni/dev-contract.git","type":"git"},"_npmVersion":"12.0.2","description":"Standardized dev-start/dev-auth process contract for the Amadeni project fleet: ready means a verified login","directories":{},"maintainers":[{"name":"amadeni_ai","email":"admin@amadeni.ai"}],"sideEffects":false,"_nodeVersion":"22.23.2","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"packageManager":"pnpm@10.7.0+sha512.6b865ad4b62a1d9842b61d674a393903b871d9244954f652b8842c2b553c72176b278f64c463e52d40fff8aba385c235c8c9ecf5cc7de4fd78b8bb6d49633ab6","devDependencies":{"cspell":"^9.7.0","eslint":"^10.0.2","vitest":"^4.0.18","prettier":"^3.8.1","@eslint/js":"^10.0.1","typescript":"^5.9.0","@types/node":"^25.3.3","typescript-eslint":"^8.56.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dev-contract_0.2.0_1789422062739_0.3064039582992131"}}},"time":{"created":"2026-08-12T17:47:03.353Z","modified":"2026-09-14T21:41:03.240Z","0.1.0":"2026-08-12T17:47:03.844Z","0.1.1":"2026-08-12T22:25:14.870Z","0.1.2":"2026-09-14T11:06:38.755Z","0.2.0":"2026-09-14T21:41:02.840Z"},"bugs":{"url":"https://github.com/amadeni/dev-contract/issues"},"author":{"name":"Amadeni","email":"nicolai.hallberg@amadeni.ai"},"license":"MIT","homepage":"https://github.com/amadeni/dev-contract#readme","keywords":["convex","nextjs","dev-environment","better-auth","cli","automation"],"repository":{"url":"git+https://github.com/amadeni/dev-contract.git","type":"git"},"description":"Standardized dev-start/dev-auth process contract for the Amadeni project fleet: ready means a verified login","maintainers":[{"name":"amadeni_ai","email":"admin@amadeni.ai"}],"readme":"# @amadeni/dev-contract\n\nStandardized dev-start/dev-auth process contract for the Amadeni project\nfleet. One CLI replaces the per-repo shell scripts (`dev-start.sh` /\n`dev-auth.sh` / `dev-stop.sh`) that every project used to copy — with one\ncore guarantee the scripts never gave:\n\n> **ready = verified login.** `dev-contract start` only reports ready\n> after a dev login has DEMONSTRABLY worked: it mints a single-use token,\n> consumes it at the magic link verify endpoint, and replays the issued\n> cookies against an authenticated probe until the response proves a live\n> session. The pipeline receives a ready-made authenticated state\n> (cookies + Convex JWT), not just URLs — the \"screenshot shows the login\n> screen instead of the app\" failure mode cannot pass the gate.\n\n## What `start` does\n\n1. Starts `convex dev` (detached process group, pid + log files in\n   `.dev-contract/`). Fresh checkouts get `CONVEX_AGENT_MODE=anonymous` so\n   Convex picks a local anonymous deployment without prompting. Readiness\n   means the backend answers **and** `convex dev` has reported\n   `Convex functions ready` for this start — on a fresh deployment the\n   push lands seconds after the backend, and nothing (seed, token mint)\n   calls a function before it did.\n2. **Guard (hard abort):** provisioning only ever happens against a\n   `dev:*` or `anonymous:*` `CONVEX_DEPLOYMENT` (and only local\n   `CONVEX_SELF_HOSTED_URL` hosts). Anything else exits non-zero before a\n   single env var is written.\n3. Provisions missing dev env vars on the Convex deployment:\n   `AMADENI_DEV_AUTH_ENABLED=true`, a generated `BETTER_AUTH_SECRET`, and\n   `SITE_URL` — reconciled on every start, so repaired environments heal.\n4. **Seed (optional):** runs the `base` seed profile — after the backend\n   is ready and provisioned, before the login gate — so the test user /\n   base data exist before the login is verified. A failing seed aborts\n   the start with a `[seed]` diagnosis; there is no \"ready\" on top of a\n   broken seed. Other profiles (`full`) only run on request. See\n   [Seeding](#seeding-optional).\n5. Starts the app dev server and waits for HTTP.\n6. **Readiness gate:** retries mint → verify → session-probe until the\n   login is verified (or the deadline passes — then it fails loudly with\n   the step that broke). A second, unused token becomes `auth.loginUrl`\n   for browser consumers.\n7. Emits the contract JSON as the **last stdout line** (all logging goes\n   to stderr):\n\n```json\n{\n  \"ok\": true,\n  \"baseUrl\": \"http://localhost:3001\",\n  \"appUrl\": \"http://localhost:3001\",\n  \"convexUrl\": \"https://<deployment>.convex.cloud\",\n  \"convexSiteUrl\": \"https://<deployment>.convex.site\",\n  \"auth\": {\n    \"email\": \"dev@amadeni.local\",\n    \"cookie\": \"better-auth.session_token=...; better-auth.convex_jwt=...\",\n    \"cookies\": {\n      \"better-auth.session_token\": \"...\",\n      \"better-auth.convex_jwt\": \"...\"\n    },\n    \"convexJwt\": \"<decoded JWT for ConvexHttpClient.setAuth()>\",\n    \"loginUrl\": \"http://localhost:3001/api/auth/magic-link/verify?token=...\"\n  },\n  \"readyAt\": \"2026-01-02T03:04:05.000Z\",\n  \"pids\": { \"convex\": 123, \"app\": 456 },\n  \"stateDir\": \"/abs/path/.dev-contract\"\n}\n```\n\nFailures never emit `ok: true`: the process exits non-zero with a\n`[step]`-prefixed diagnosis on stderr (`guard`, `convex-ready`,\n`provision`, `seed`, `app-ready`, `mint-token`, `verify`,\n`session-probe`, `login-ready`, ...).\n\n## Commands\n\n```bash\ndev-contract start [--config path] [--email x] [--out file] [--root dir]\ndev-contract auth   # fresh verified session for a running environment\ndev-contract seed [--profile <name>]   # run one seed profile (default: base)\ndev-contract stop   # stop the process groups started by `start`\n```\n\n`auth` emits `{ \"ok\": true, \"loginUrl\": ..., \"baseUrl\": ..., \"auth\": {...} }`;\n`seed` emits `{ \"ok\": true, \"profile\": \"full\", \"ran\": [\"command\", \"function\"] }`;\n`stop` emits `{ \"ok\": true, \"stopped\": [...] }`.\n\n## Seeding (optional)\n\nProjects that need base data (a test user, org fixtures, e2e profiles)\nbefore the first login declare a `seed` block in the config. The\ntop-level `command` / `function` / `args` are the **`base` profile**;\nfurther profiles live in `seed.profiles`:\n\n```json\n{\n  \"seed\": {\n    \"command\": \"pnpm run seed:dev\",\n    \"function\": \"testSupport/seed:ensureBaseData\",\n    \"args\": { \"profile\": \"e2e\" },\n    \"profiles\": {\n      \"full\": {\n        \"function\": \"testSupport/seed:ensureFixture\",\n        \"args\": { \"scenario\": \"review\" }\n      }\n    }\n  },\n  \"timeouts\": { \"seedMs\": 300000 }\n}\n```\n\n- **`command`** is run as a shell command in the project root.\n- **`function`** is run via `npx convex run` (typecheck/codegen disabled,\n  `auth.identity` attached when configured — identity-gated seed\n  functions work exactly like the token function).\n- Every profile needs at least one of the two; with both set, `command`\n  runs first.\n- **Profiles.** `base` is what `start` runs (after backend readiness +\n  provisioning, before the auth/login gate) and what `dev-contract seed`\n  runs without `--profile`. `profiles.base` may replace the top-level\n  block, but declaring both is a config error. Any other name only ever\n  runs on request: `dev-contract seed --profile <name>`. A block with\n  only `profiles` (no `base`) is fine — `start` then seeds nothing.\n- **`full` is the fleet convention** for the complete test fixture\n  (`just dev-seed full` in the fleet contract): Mynd's executor runs it\n  once after `dev-start` and before `dev-auth`, with a 5-minute budget,\n  one attempt, failure = warning. Profile names are shell-safe\n  (`[A-Za-z0-9_-]`).\n- **`timeouts.seedMs`** (default 300 000 ms) is the budget for one seed\n  profile — it applies to `command` and to `function` each. A timeout\n  kills the process and fails the seed with `[timeout]` in the\n  diagnosis.\n- An unknown profile fails with `[seed] unknown profile <name>` on\n  stderr and a non-zero exit — never a silent no-op.\n- **Every profile MUST be idempotent** (insert-only, or probe-then-insert\n  like the Hub's `ensure_seed`): the contract re-runs `base` on every\n  `start` and `full` on every review iteration. Wipe-and-recreate seeds\n  do not belong here; `full` should be additive on top of `base`.\n- Any seed failure is a hard abort with a `[seed]`-prefixed diagnosis —\n  the environment is never reported ready on a broken seed.\n- The deployment guard applies: seeding (like everything that writes) is\n  only ever allowed against `dev:*` / `anonymous:*` deployments.\n\n## Project integration\n\n### 1. Config: `devcontract.config.json` in the repo root\n\nSee [`devcontract.config.example.json`](./devcontract.config.example.json).\nMinimal version:\n\n```json\n{\n  \"appUrl\": \"http://localhost:3001\",\n  \"auth\": {\n    \"createTokenFunction\": \"dev/auth:createDevToken\",\n    \"identity\": { \"issuer\": \"my-app-dev-auth\", \"subject\": \"dev-auth-cli\" }\n  }\n}\n```\n\nEverything else has defaults (`pnpm`, `convex dev`, `next dev -p <port>`,\nbetter-auth verify/get-session paths, 120s/120s/90s timeouts, 300s per\nseed profile).\n\n### 2. Convex-side fixture: `createDevAuth` from `@amadeni/better-auth-kit`\n\nThe token function referenced by `auth.createTokenFunction` lives in the\napp's `convex/` directory and is a thin wiring of the kit factory\n(v0.3.0+). It writes a hashed magic-link verification row directly into\nthe Better Auth component — the login then runs through the app's regular\nverify endpoint, with real sessions and cookies:\n\n```ts\n// convex/dev/auth.ts\nimport { v } from 'convex/values';\nimport {\n  createDevAuth,\n  requireDevAuthCliIdentity,\n} from '@amadeni/better-auth-kit';\nimport { action } from '../_generated/server';\nimport { components, internal } from '../_generated/api';\n\nconst devAuth = createDevAuth({\n  createVerification: (ctx, input) =>\n    ctx.runMutation(components.betterAuth.adapter.create, { input }),\n  ensureUser: (ctx, { email, name }) =>\n    ctx.runMutation(internal.dev.auth.ensureDevUserInternal, { email, name }),\n});\n\nexport const createDevToken = action({\n  args: { email: v.optional(v.string()) },\n  handler: async (ctx, args) => {\n    await requireDevAuthCliIdentity(ctx, {\n      issuer: 'my-app-dev-auth', // must match devcontract.config.json\n      subject: 'dev-auth-cli',\n    });\n    return await devAuth.issueToken(ctx, args);\n  },\n});\n```\n\nThe kit enforces the hard gate: minting throws unless\n`AMADENI_DEV_AUTH_ENABLED === 'true'`, and always throws on\nproduction-shaped deployments. **Never set that variable on production.**\n\nApps with existing dev-auth actions (e.g. the Hub's\n`dev/auth:createDevToken`) work as-is — the contract only requires \"takes\n`{ email? }`, returns `{ token }`\".\n\n### 3. Optional: keep the `just` recipes as thin wrappers\n\n```just\ndev-start:\n    pnpm exec dev-contract start\n\ndev-auth:\n    pnpm exec dev-contract auth\n\ndev-seed profile='base':\n    pnpm exec dev-contract seed --profile {{profile}}\n\ndev-stop:\n    pnpm exec dev-contract stop\n```\n\n## Consumer notes (Mynd / pipelines)\n\n- **Legacy compatibility:** the previous shell contract emitted\n  `{\"baseUrl\": ...}` (dev-start) and `{\"loginUrl\": ...}` (dev-auth) as the\n  last stdout line. The new output is a strict superset: `baseUrl` stays\n  top-level in `start`, `loginUrl` stays top-level in `auth`. Existing\n  parsers (`parseDevStartOutput` / `parseDevAuthOutput`) keep working\n  unchanged.\n- **The upgrade:** consumers should switch from \"open loginUrl and hope\"\n  to injecting the delivered state directly — set `auth.cookie` as the\n  `Cookie` header (or seed the browser context's cookies) and/or use\n  `auth.convexJwt` with `ConvexHttpClient.setAuth()`. `loginUrl` remains\n  for pure-browser flows; it carries a fresh unused single-use token.\n- **Trust the exit code, not the log tail:** exit 0 + last-line JSON with\n  `ok: true` is the only ready signal; the JSON is only emitted after the\n  verified-login gate passed. On failure the exit code is non-zero and\n  stderr names the failing step.\n- `start` is idempotent: running processes are reused, env state is\n  re-reconciled, and the login is re-verified on every call — safe to call\n  once per review iteration.\n- **Test fixture:** `dev-contract seed --profile full` (= `just dev-seed\nfull`) between `start` and `auth`; the last stdout line is\n  `{ \"ok\": true, \"profile\": \"full\", \"ran\": [...] }`. Treat a non-zero exit\n  as a warning about the fixture, not as \"environment not ready\".\n\n## Programmatic use\n\n```ts\nimport { loadConfig, runStart } from '@amadeni/dev-contract';\n\nconst config = await loadConfig(projectRoot);\nconst result = await runStart(config); // throws DevContractError with .step\n```\n\n## Security posture\n\n- Provisioning is hard-gated to `dev:*` / `anonymous:*` deployments —\n  the CLI refuses everything else before writing anything.\n- The dev login itself is additionally gated Convex-side by\n  `@amadeni/better-auth-kit`'s `assertDevAuthEnabled` (exact-match env\n  flag + production-shape refusal).\n- Zero runtime dependencies; Node >= 20.\n\n## Development\n\n```bash\npnpm install\npnpm run ci    # prettier + eslint + tsc + cspell + vitest\n```\n","readmeFilename":"README.md"}