diff --git a/text/0985-v2-addon-by-default.md b/text/0985-v2-addon-by-default.md
new file mode 100644
index 0000000000..442b47aa19
--- /dev/null
+++ b/text/0985-v2-addon-by-default.md
@@ -0,0 +1,898 @@
+---
+stage: accepted
+start-date: 2023-11-02T16:05:11.000Z
+release-date: # In format YYYY-MM-DDT00:00:00.000Z
+release-versions:
+teams: # delete teams that aren't relevant
+ - cli
+ - data
+ - framework
+prs:
+ accepted: https://github.com/emberjs/rfcs/pull/985
+project-link:
+suite:
+---
+
+# Change the default addon blueprint to `@ember/addon-blueprint`
+
+## Summary
+
+Make [`@ember/addon-blueprint`](https://github.com/ember-cli/ember-addon-blueprint) the default blueprint for new Ember addons, replacing the current v1 and v2 blueprints.
+
+## Motivation
+
+The current default blueprints have real problems:
+
+**V1 addons** get rebuilt by every consuming app, which is slow and couples addon builds to app builds.
+
+**The original V2 blueprint** fixed the build problem but required a monorepo and manual configuration. It also lacked TypeScript/Glint integration and modern Ember patterns.
+
+`@ember/addon-blueprint` fixes these by defaulting to a single-package structure, integrating Glint for template type safety, using native classes and strict mode throughout, and providing sensible tooling defaults out of the box.
+
+## Detailed design
+
+### Definitions
+
+**V2 Addon**: An addon with `ember-addon.version: 2` in package.json, as defined by RFC 507.
+
+**Single-package addon**: An addon with its test suite in the same package, rather than a separate test app in a monorepo.
+
+**Blueprint**: A code generation template used by ember-cli to scaffold projects.
+
+### Blueprint Structure
+
+```
+my-addon/
+├── .github/
+│ └── workflows/
+│ ├── ci.yml # CI pipeline
+│ └── push-dist.yml # Publish to dist branch
+├── src/ # Source code (published)
+│ ├── index.js # Main entry point
+│ └── template-registry.ts # Glint type registry
+├── tests/ # Test files
+│ ├── index.html # Test runner page
+│ └── test-helper.ts # Test setup
+├── demo-app/ # Demo application
+│ ├── app.gts # Demo app entry point
+│ ├── styles.css
+│ └── templates/
+├── unpublished-development-types/ # Dev-only types
+│ └── index.d.ts
+├── config/
+│ └── ember-cli-update.json # Blueprint version tracking
+├── dist/ # Built output (gitignored, published)
+├── declarations/ # TS declarations (gitignored, published)
+├── package.json
+├── index.html # Demo app entry page
+├── rollup.config.mjs # Production build
+├── vite.config.mjs # Dev build + tests
+├── tsconfig.json # Dev TypeScript config
+├── tsconfig.publish.json # Publish TypeScript config
+├── babel.config.cjs # Dev Babel config
+├── babel.publish.config.cjs # Publish Babel config
+├── eslint.config.mjs # ESLint flat config
+├── .prettierrc.mjs # Prettier config
+├── .prettierignore
+├── .template-lintrc.mjs # Template linting
+├── testem.cjs # Test runner config
+├── .try.mjs # Ember version scenarios
+├── .editorconfig
+├── .env.development
+├── .gitignore
+├── README.md
+├── CONTRIBUTING.md
+├── LICENSE.md
+└── addon-main.cjs # V1 compat shim
+```
+
+**Why single-package by default**: Most addons don't need a monorepo. Single-package is simpler to maintain and publish. Advanced users can still set up monorepos.
+
+**Why dual build systems**: Vite gives fast dev rebuilds and HMR. Rollup gives optimized, tree-shaken production output. Tests run entirely through Vite, no webpack or `ember-auto-import` needed.
+
+**Why Glint**: Template type safety via Volar-based TS server plugins. Works for both TypeScript and JavaScript projects.
+
+### Package Configuration
+
+> [!NOTE]
+> This is an overview. Exact contents can change as needs evolve. We aim to cover the 80% use case without restricting anyone who needs more.
+
+#### package.json
+
+```json
+{
+ "name": "<%= name %>",
+ "version": "0.0.0",
+ "description": "The default blueprint for Embroider v2 addons.",
+ "keywords": ["ember-addon"],
+ "repository": "",
+ "license": "MIT",
+ "author": "",
+ "files": [
+ "addon-main.cjs",
+ "declarations",
+ "dist",
+ "src"
+ ],
+ "ember": {
+ "edition": "octane"
+ },
+ "ember-addon": {
+ "version": 2,
+ "type": "addon",
+ "main": "addon-main.cjs"
+ },
+ "imports": {
+ "#src/*": "./src/*"
+ },
+ "exports": {
+ ".": {
+ "types": "./declarations/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "./addon-main.js": "./addon-main.cjs",
+ "./*.css": "./dist/*.css",
+ "./*": {
+ "types": "./declarations/*.d.ts",
+ "default": "./dist/*.js"
+ }
+ }
+}
+```
+
+`exports` maps consumer-facing imports to the right files (declarations for types, dist for runtime). `imports` with `#src/*` gives tests and the demo app a clean way to import from source without rebuilding -- but can't be used in `src/` itself because Rollup won't transform those imports.
+
+The `files` array includes `src` alongside `dist` and `declarations` so consumers get source-level go-to-definition in their editors.
+
+#### Development vs. Production Configs
+
+The blueprint splits config into dev and publish variants. This is the key architectural pattern throughout:
+
+- **Dev configs** (`babel.config.cjs`, `tsconfig.json`, `vite.config.mjs`) include macro evaluation, compat transforms, Vite/Embroider types, and test infrastructure
+- **Publish configs** (`babel.publish.config.cjs`, `tsconfig.publish.json`, `rollup.config.mjs`) use minimal transforms and omit dev-only APIs
+
+This split matters because macros should be evaluated by the consuming app (not baked in at publish time), and `lint:types` against the publish tsconfig catches accidental usage of Vite or Embroider internals in published code.
+
+#### Vite Config (`vite.config.mjs`)
+
+```javascript
+import { defineConfig } from 'vite';
+import { extensions, ember, classicEmberSupport } from '@embroider/vite';
+import { babel } from '@rollup/plugin-babel';
+
+// For scenario testing
+const isCompat = Boolean(process.env.ENABLE_COMPAT_BUILD);
+
+export default defineConfig({
+ plugins: [
+ ...(isCompat ? [classicEmberSupport()] : []),
+ ember(),
+ babel({
+ babelHelpers: 'inline',
+ extensions,
+ }),
+ ],
+ build: {
+ rollupOptions: {
+ input: {
+ tests: 'tests/index.html',
+ },
+ },
+ },
+});
+```
+
+#### Rollup Config (`rollup.config.mjs`)
+
+```javascript
+import { babel } from '@rollup/plugin-babel';
+import { Addon } from '@embroider/addon-dev/rollup';
+import { fileURLToPath } from 'node:url';
+import { resolve, dirname } from 'node:path';
+
+const addon = new Addon({
+ srcDir: 'src',
+ destDir: 'dist',
+});
+
+const rootDirectory = dirname(fileURLToPath(import.meta.url));
+const babelConfig = resolve(rootDirectory, './babel.publish.config.cjs');
+const tsConfig = resolve(rootDirectory, './tsconfig.publish.json');
+
+export default {
+ output: addon.output(),
+ plugins: [
+ addon.publicEntrypoints(['**/*.js', 'index.js', 'template-registry.js']),
+ addon.appReexports([
+ 'components/**/*.js',
+ 'helpers/**/*.js',
+ 'modifiers/**/*.js',
+ 'services/**/*.js',
+ ]),
+ addon.dependencies(),
+ babel({
+ extensions: ['.js', '.gjs', '.ts', '.gts'],
+ babelHelpers: 'bundled',
+ configFile: babelConfig,
+ }),
+ addon.hbs(),
+ addon.gjs(),
+ // Emit .d.ts declaration files
+ addon.declarations(
+ 'declarations',
+ `npx @glint/ember-tsc -- --declaration --project ${tsConfig}`,
+ ),
+ addon.keepAssets(['**/*.css']),
+ addon.clean(),
+ ],
+};
+```
+
+### TypeScript and Glint
+
+TypeScript is opt-in via `--typescript`.
+
+The blueprint uses two tsconfigs:
+
+**`tsconfig.json`** (dev) -- includes `src/`, `tests/`, `demo-app/`, and `unpublished-development-types/`. Has Vite and Embroider types so your editor works.
+
+```json
+{
+ "extends": "@ember/app-tsconfig",
+ "include": [
+ "src/**/*",
+ "tests/**/*",
+ "unpublished-development-types/**/*",
+ "demo-app/**/*"
+ ],
+ "compilerOptions": {
+ "rootDir": ".",
+ "types": [
+ "ember-source/types",
+ "vite/client",
+ "@embroider/core/virtual",
+ "@glint/ember-tsc/types"
+ ]
+ }
+}
+```
+
+**`tsconfig.publish.json`** -- only `src/` and dev types. No Vite or Embroider types, so `lint:types` catches accidental usage of dev-only APIs in published code.
+
+```json
+{
+ "extends": "@ember/library-tsconfig",
+ "include": ["./src/**/*", "./unpublished-development-types/**/*"],
+ "compilerOptions": {
+ "allowJs": true,
+ "declarationDir": "declarations",
+ "rootDir": "./src",
+ "types": ["ember-source/types", "@glint/ember-tsc/types"]
+ }
+}
+```
+
+The Glint template registry (`src/template-registry.ts`) lets apps using loose mode (hbs files) consume your types. Not needed if your library only targets strict mode consumers.
+
+### The Strict Resolver and `modules`
+
+Both the test helper and the demo app use `ember-strict-application-resolver` instead of the classic Ember resolver. Instead of filesystem conventions, you explicitly register modules via a `modules` object. Each key must match a `./[type]/[name]` pattern (see [RFC 1132](https://rfcs.emberjs.com/id/1132-default-strict-resolver)):
+
+```typescript
+class MyApp extends EmberApp {
+ modules = {
+ './router': Router, // direct assignment
+ './services/page-title': PageTitleService, // explicit import
+ ...import.meta.glob('./services/**/*', { eager: true }), // bulk registration
+ ...import.meta.glob('./templates/**/*', { eager: true }),
+ };
+}
+```
+
+You can register modules individually (useful for things from dependencies) or use `import.meta.glob` to sweep up everything in a directory. The glob approach is convenient but imports everything matching the pattern -- if you have non-service files in `services/`, they'll get pulled in too.
+
+This pattern is used in two places:
+
+- **Test helper** -- registers a minimal Router and optionally any services needed for tests
+- **Demo app** -- registers the Router, templates, services, and anything else the demo needs
+
+### Demo App
+
+The blueprint includes a small demo application for manually testing your addon during development. Run `npm start` (or `pnpm start`) to launch Vite's dev server, which serves the root `index.html`:
+
+**`index.html`**:
+```html
+
+
+
+
+ Demo App
+
+
+
+
+
+
+
+```
+
+**`demo-app/app.gts`**:
+```typescript
+import EmberApp from 'ember-strict-application-resolver';
+import EmberRouter from '@ember/routing/router';
+import PageTitleService from 'ember-page-title/services/page-title';
+
+class Router extends EmberRouter {
+ location = 'history';
+ rootURL = '/';
+}
+
+export class App extends EmberApp {
+ modules = {
+ './router': Router,
+ './services/page-title': PageTitleService,
+ ...import.meta.glob('./services/**/*', { eager: true }),
+ ...import.meta.glob('./templates/**/*', { eager: true }),
+ };
+}
+
+Router.map(function () {});
+```
+
+The demo app is a real Ember app -- it has routes, templates, and services -- but it boots directly via `ember-strict-application-resolver` with no ember-cli build step. Any addon code you want to exercise in the demo needs to be imported in the demo app's templates or registered in `modules`. The demo app's files are not published (they're not in the `files` array or `exports`).
+
+### Testing
+
+Tests also run entirely on Vite -- no ember-cli build pipeline, no webpack.
+
+**`tests/test-helper.ts`**:
+```typescript
+import EmberApp from 'ember-strict-application-resolver';
+import EmberRouter from '@ember/routing/router';
+import * as QUnit from 'qunit';
+import { setApplication } from '@ember/test-helpers';
+import { setup } from 'qunit-dom';
+import { start as qunitStart, setupEmberOnerrorValidation } from 'ember-qunit';
+import { setTesting } from '@embroider/macros';
+
+class Router extends EmberRouter {
+ location = 'none';
+ rootURL = '/';
+}
+
+class TestApp extends EmberApp {
+ modules = {
+ './router': Router,
+ // add any custom services here
+ // import.meta.glob('./services/*', { eager: true }),
+ };
+}
+
+Router.map(function () {});
+
+export function start() {
+ setTesting(true);
+ setApplication(
+ TestApp.create({
+ autoboot: false,
+ rootElement: '#ember-testing',
+ }),
+ );
+ setup(QUnit.assert);
+ setupEmberOnerrorValidation();
+ qunitStart();
+}
+```
+
+**`tests/index.html`**:
+```html
+
+
+
+
+ <%= name %> Tests
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+The test app is structurally the same as the demo app -- a minimal Ember app via `ember-strict-application-resolver` -- but configured for testing (`location = 'none'`, `autoboot: false`, `setTesting(true)`). Test discovery uses `import.meta.glob` in the HTML entry point. This is also a proof-of-concept for how future compat-less Ember apps could work.
+
+#### Cross-Version Testing
+
+The `.try.mjs` config defines scenarios for testing against multiple Ember versions:
+
+```javascript
+const compatFiles = {
+ 'ember-cli-build.cjs': `const EmberApp = require('ember-cli/lib/broccoli/ember-app');
+const { compatBuild } = require('@embroider/compat');
+module.exports = async function (defaults) {
+ const { buildOnce } = await import('@embroider/vite');
+ let app = new EmberApp(defaults);
+ return compatBuild(app, buildOnce);
+};`,
+ 'config/optional-features.json': JSON.stringify({
+ 'application-template-wrapper': false,
+ 'default-async-observers': true,
+ 'jquery-integration': false,
+ 'template-only-glimmer-components': true,
+ 'no-implicit-route-model': true,
+ }),
+};
+
+const compatDeps = {
+ '@embroider/compat': '^4.0.3',
+ 'ember-cli': '^5.12.0',
+ 'ember-auto-import': '^2.10.0',
+ '@ember/optional-features': '^2.2.0',
+};
+
+export default {
+ scenarios: [
+ {
+ name: 'ember-lts-5.8',
+ npm: {
+ devDependencies: {
+ 'ember-source': '~5.8.0',
+ ...compatDeps,
+ },
+ },
+ env: {
+ ENABLE_COMPAT_BUILD: true,
+ },
+ files: compatFiles,
+ },
+ {
+ name: 'ember-lts-5.12',
+ npm: {
+ devDependencies: {
+ 'ember-source': '~5.12.0',
+ ...compatDeps,
+ },
+ },
+ env: {
+ ENABLE_COMPAT_BUILD: true,
+ },
+ files: compatFiles,
+ },
+ {
+ name: 'ember-lts-6.4',
+ npm: {
+ devDependencies: {
+ 'ember-source': 'npm:ember-source@~6.4.0',
+ },
+ },
+ },
+ {
+ name: 'ember-latest',
+ npm: {
+ devDependencies: {
+ 'ember-source': 'npm:ember-source@latest',
+ },
+ },
+ },
+ {
+ name: 'ember-beta',
+ npm: {
+ devDependencies: {
+ 'ember-source': 'npm:ember-source@beta',
+ },
+ },
+ },
+ {
+ name: 'ember-alpha',
+ npm: {
+ devDependencies: {
+ 'ember-source': 'npm:ember-source@alpha',
+ },
+ },
+ },
+ ],
+};
+```
+
+Older Ember versions (5.x) need `@embroider/compat` and an `ember-cli-build.cjs` shim. Ember 6.4+ runs natively without compat mode.
+
+### Babel Configs
+
+**Dev (`babel.config.cjs`)** -- used by your editor and tests. Includes macro evaluation and compat transforms:
+
+```javascript
+/**
+ * This babel.config is not used for publishing.
+ * It's only for the local editing experience
+ * (and linting)
+ */
+const { buildMacros } = require('@embroider/macros/babel');
+const { babelCompatSupport, templateCompatSupport } = require('@embroider/compat/babel');
+
+const macros = buildMacros();
+
+// For scenario testing
+const isCompat = Boolean(process.env.ENABLE_COMPAT_BUILD);
+
+module.exports = {
+ plugins: [
+ ['@babel/plugin-transform-typescript', {
+ allExtensions: true,
+ allowDeclareFields: true,
+ onlyRemoveTypeImports: true,
+ }],
+ ['babel-plugin-ember-template-compilation', {
+ transforms: [
+ ...(isCompat ? templateCompatSupport() : macros.templateMacros),
+ ],
+ }],
+ ['module:decorator-transforms', {
+ runtime: {
+ import: require.resolve('decorator-transforms/runtime-esm'),
+ },
+ }],
+ ...(isCompat ? babelCompatSupport() : macros.babelMacros),
+ ],
+ generatorOpts: {
+ compact: false,
+ },
+};
+```
+
+**Publish (`babel.publish.config.cjs`)** -- minimal transforms. Macros are deliberately omitted; the consuming app evaluates them:
+
+```javascript
+/**
+ * This babel.config is only used for publishing.
+ *
+ * For local dev experience, see the babel.config
+ */
+module.exports = {
+ plugins: [
+ ['@babel/plugin-transform-typescript', {
+ allExtensions: true,
+ allowDeclareFields: true,
+ onlyRemoveTypeImports: true,
+ }],
+ ['babel-plugin-ember-template-compilation', {
+ targetFormat: 'hbs',
+ transforms: [],
+ }],
+ ['module:decorator-transforms', {
+ runtime: {
+ import: 'decorator-transforms/runtime-esm',
+ },
+ }],
+ ],
+ generatorOpts: {
+ compact: false,
+ },
+};
+```
+
+### Linting
+
+**ESLint** uses flat config (`eslint.config.mjs`) with `defineConfig` and `globalIgnores`:
+
+```javascript
+import babelParser from '@babel/eslint-parser/experimental-worker';
+import js from '@eslint/js';
+import { defineConfig, globalIgnores } from 'eslint/config';
+import prettier from 'eslint-config-prettier';
+import ember from 'eslint-plugin-ember/recommended';
+import importPlugin from 'eslint-plugin-import';
+import n from 'eslint-plugin-n';
+import globals from 'globals';
+import ts from 'typescript-eslint';
+
+const esmParserOptions = {
+ ecmaFeatures: { modules: true },
+ ecmaVersion: 'latest',
+};
+
+const tsParserOptions = {
+ projectService: true,
+ tsconfigRootDir: import.meta.dirname,
+};
+
+export default defineConfig([
+ globalIgnores(['dist/', 'dist-*/', 'declarations/', 'coverage/', '!**/.*']),
+ js.configs.recommended,
+ prettier,
+ ember.configs.base,
+ ember.configs.gjs,
+ ember.configs.gts,
+ {
+ linterOptions: {
+ reportUnusedDisableDirectives: 'error',
+ },
+ },
+ {
+ files: ['**/*.js'],
+ languageOptions: {
+ parser: babelParser,
+ },
+ },
+ {
+ files: ['**/*.{js,gjs}'],
+ languageOptions: {
+ parserOptions: esmParserOptions,
+ globals: { ...globals.browser },
+ },
+ },
+ {
+ files: ['**/*.{ts,gts}'],
+ languageOptions: {
+ parser: ember.parser,
+ parserOptions: tsParserOptions,
+ globals: { ...globals.browser },
+ },
+ extends: [
+ ...ts.configs.recommendedTypeChecked,
+ { ...ts.configs.eslintRecommended, files: undefined },
+ ember.configs.gts,
+ ],
+ },
+ {
+ files: ['src/**/*'],
+ plugins: { import: importPlugin },
+ rules: {
+ 'import/extensions': ['error', 'always', { ignorePackages: true }],
+ },
+ },
+ // ... additional CJS/ESM node file configurations
+]);
+```
+
+Type-aware linting via `projectService`, Ember .gjs/.gts support, and enforced file extensions in `src/` imports.
+
+**Template linting** (`.template-lintrc.mjs`):
+```javascript
+export default {
+ extends: 'recommended',
+ checkHbsTemplateLiterals: false,
+};
+```
+
+**Prettier** (`.prettierrc.mjs`):
+```javascript
+export default {
+ plugins: ['prettier-plugin-ember-template-tag'],
+ overrides: [
+ {
+ files: '*.{js,gjs,ts,gts,mjs,mts,cjs,cts}',
+ options: {
+ singleQuote: true,
+ templateSingleQuote: false,
+ },
+ },
+ ],
+};
+```
+
+### CI/CD
+
+The blueprint generates GitHub Actions workflows (shown here with pnpm; npm/yarn variants are also generated):
+
+**CI workflow** (`ci.yml`):
+- **Lint** -- runs `pnpm lint` (ESLint, Prettier, template-lint, type checking)
+- **Test** -- runs `pnpm test`, then outputs a scenario matrix via `@embroider/try list`
+- **Floating deps** -- installs without lockfile, runs tests to catch compatibility issues early
+- **Try scenarios** -- matrix job that applies each `.try.mjs` scenario and runs tests against it
+
+```yaml
+try-scenarios:
+ name: ${{ matrix.name }}
+ runs-on: ubuntu-latest
+ needs: "test"
+ timeout-minutes: 10
+ strategy:
+ fail-fast: false
+ matrix: ${{fromJson(needs.test.outputs.matrix)}}
+ steps:
+ - name: Apply Scenario
+ run: pnpm dlx @embroider/try apply ${{ matrix.name }}
+ - name: Install Dependencies
+ run: pnpm install --no-lockfile
+ - name: Run Tests
+ run: pnpm test
+ env: ${{ matrix.env }}
+```
+
+**Push dist workflow** (`push-dist.yml`) -- on push to main, builds the addon and pushes compiled assets to a `dist` branch for git-based consumption.
+
+### V1 Compatibility
+
+```javascript
+// addon-main.cjs
+'use strict';
+const { addonV1Shim } = require('@embroider/addon-shim');
+module.exports = addonV1Shim(__dirname);
+```
+
+This shim translates V2 package metadata into V1 build hooks so the addon works in classic ember-cli apps.
+
+### Influence on Future App Blueprint
+
+The test setup here is a proof-of-concept for future compat-less Ember apps:
+
+- A minimal Ember app running on Vite with no webpack or `ember-cli-build.js`
+- Bootstrap with just `EmberApp` and `EmberRouter` -- no complex build pipeline
+- ES modules and `import.meta.glob` for module discovery instead of AMD/requirejs
+- Direct framework API usage instead of ember-cli abstractions
+
+This validates that Ember apps can run well on modern build tools, pointing toward simpler app blueprints in the future.
+
+### Migration
+
+Existing addons are unaffected. New addons get the new blueprint automatically. Existing addons can migrate by generating a new project and copying relevant files, or using `npx ember-cli@latest addon --blueprint @ember/addon-blueprint`.
+
+## How we teach this
+
+### Documentation Updates
+
+- Update the Ember Guides and CLI docs to reference the new blueprint
+- The blueprint README covers customization, publishing, and multi-version support
+- Provide migration guides for v1 and v2 addon authors
+
+### Key Concepts for Addon Authors
+
+#### `exports` and `imports`
+
+`exports` defines your addon's public API:
+
+```json
+{
+ "exports": {
+ ".": {
+ "types": "./declarations/index.d.ts",
+ "default": "./dist/index.js"
+ },
+ "./*.css": "./dist/*.css",
+ "./*": {
+ "types": "./declarations/*.d.ts",
+ "default": "./dist/*.js"
+ }
+ }
+}
+```
+
+`imports` with `#src/*` lets tests and the demo app import from source without rebuilding. Can't be used in `src/` (Rollup won't transform these). Files in `src/` must use relative imports.
+
+#### Importing Addon Code in Tests: `#src/*` vs. Consumer-Style
+
+When writing tests, you have two ways to import from your addon:
+
+**`#src/*` imports** -- import directly from source files:
+```javascript
+import { myHelper } from '#src/helpers/my-helper';
+```
+- Works immediately, no build step needed
+- Fast feedback loop during development
+- Tests the source code directly
+
+**Consumer-style imports** -- import as a consumer would:
+```javascript
+import { myHelper } from 'my-addon/helpers/my-helper';
+```
+- Tests the published API surface
+- Requires `dist/` to exist (needs a build first)
+- Catches issues with `exports` mapping or build transforms
+
+**Recommendation**: Use `#src/*` imports for day-to-day development. The try-scenarios CI matrix will catch build/export issues by running against real builds. If you need to specifically test the published output, use consumer-style imports in a dedicated test file and run `npm run build` first.
+
+#### Self-Imports
+
+Self-imports (e.g. `import { x } from 'my-addon/foo'`) don't work during development in `src/` files because they resolve through `exports` to `dist/`, which doesn't exist until you build. Use relative imports in `src/`:
+
+```javascript
+// In src/ files:
+import { myHelper } from './helpers/my-helper'; // yes
+import { myHelper } from 'my-addon/helpers/my-helper'; // no
+```
+
+#### Dev vs. Publish Configs
+
+| Purpose | Dev | Publish |
+|---------|-----|---------|
+| Babel | `babel.config.cjs` (macros, compat) | `babel.publish.config.cjs` (minimal) |
+| TypeScript | `tsconfig.json` (all files, Vite types) | `tsconfig.publish.json` (src only) |
+| Build | `vite.config.mjs` (HMR, tests) | `rollup.config.mjs` (tree-shaking) |
+
+Macros are evaluated in dev for testing but left unevaluated in published output -- the consuming app handles them. The publish tsconfig omits Vite/Embroider types so `lint:types` catches accidental usage.
+
+#### Monorepo Setup
+
+The single-package default works for most addons. If you need a monorepo (complex integration testing, multiple related packages, full documentation app):
+
+1. Generate addon: `npx ember-cli@latest addon my-addon --blueprint @ember/addon-blueprint --skip-git`
+2. Remove generated test infrastructure
+3. Generate test app: `npx ember-cli@latest app test-app --blueprint @ember/app-blueprint`
+4. Set up workspace tooling (pnpm/yarn workspaces)
+5. Install addon in test app
+
+#### Unpublished Addons in a Monorepo
+
+Sometimes you have a v2 addon in a monorepo that's only consumed by other packages in the workspace -- it's never published to npm. In this case you can skip the build step entirely and point `exports` at your source files:
+
+```json
+{
+ "name": "my-internal-addon",
+ "ember-addon": {
+ "version": 2,
+ "type": "addon",
+ "main": "addon-main.cjs"
+ },
+ "exports": {
+ ".": {
+ "types": "./src/index.ts",
+ "default": "./src/index.ts"
+ },
+ "./*": {
+ "types": "./src/*.ts",
+ "default": "./src/*.ts"
+ }
+ }
+}
+```
+
+Key differences from a published addon:
+- `exports` points to `src/` instead of `dist/` and `declarations/`
+- No `files` array needed (not publishing to npm)
+- No rollup build, no `prepack` script, no `declarations/` directory
+- No `babel.publish.config.cjs` or `tsconfig.publish.json` needed
+- You still need `addon-main.cjs` if any consuming app in the workspace uses the classic ember-cli build
+
+The consuming app's build tooling (Vite/Embroider) handles the transpilation. This is much simpler to maintain for workspace-internal code.
+
+#### Publishing
+
+1. Write code in `src/`, tests with `#src/*` imports
+2. `npm run build` runs Rollup with publish configs, producing `dist/` and `declarations/`
+3. `npm publish` ships only `files` from package.json
+4. Consumers import via `exports`, not internal paths
+
+### Resources
+
+- [@ember/addon-blueprint README](https://github.com/emberjs/ember-addon-blueprint#readme)
+- [Addon Author Guide](https://github.com/embroider-build/embroider/blob/main/docs/addon-author-guide.md)
+- [Porting Addons to V2](https://github.com/embroider-build/embroider/blob/main/docs/porting-addons-to-v2.md)
+- [Node.js Package Exports](https://nodejs.org/api/packages.html#exports)
+- [Glint Documentation](https://typed-ember.gitbook.io/glint/)
+
+## Drawbacks
+
+- Some advanced use cases (monorepos, custom builds) need additional configuration.
+- Addon authors unfamiliar with TypeScript/Glint face a learning curve, but JavaScript is fully supported.
+- The blueprint is opinionated, but covers the vast majority of use cases.
+
+## Alternatives
+
+- Do nothing (keeps old blueprints, hinders modernization)
+- Default to monorepo (too complex for most users)
+- Provide multiple blueprints (maintenance burden, confusion)
+
+## Unresolved questions
+
+- How to best support advanced monorepo setups in the future.
+- How to streamline migration for large, complex v1/v2 addons.