From 50f908078b3936a4d2719bbe24cc3ac89ad70137 Mon Sep 17 00:00:00 2001 From: Ben Girone Date: Mon, 21 Sep 2026 18:35:13 -0500 Subject: [PATCH 1/5] Add DECISIONS.md guidance to starter AGENTS.md Fusion's project-shape questionnaire already writes DECISIONS.md before the first build and injects a one-time read instruction into that first prompt (ai-services render-shape-decisions.ts). Make the same rule durable across every later session, and add the missing half: update DECISIONS.md when the user changes one of those decisions in chat. Co-Authored-By: Claude Sonnet 5 --- .github/starter-patch/apply.mjs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/starter-patch/apply.mjs b/.github/starter-patch/apply.mjs index 2d5ab7a..035c69c 100644 --- a/.github/starter-patch/apply.mjs +++ b/.github/starter-patch/apply.mjs @@ -208,6 +208,22 @@ the files actually show the starter's placeholder content.`, `# App — Agent Guide`, ); + // Fusion's project-shape questionnaire writes `DECISIONS.md` before the + // first build (see ai-services `render-shape-decisions.ts`) and injects a + // one-time instruction to read it into that first prompt. This makes the + // same rule durable across every later session, and adds the update-back + // half: nothing currently rewrites the file when a decision changes in chat. + uniqueReplace( + path.join(root, "AGENTS.md"), + `- Use \`view-screen\` or application state when the active page/selection is + unclear.`, + `- Use \`view-screen\` or application state when the active page/selection is + unclear. +- If \`DECISIONS.md\` exists at the repo root, read it before starting work — + it holds pre-build choices as current requirements. If the user changes one + later in chat, update \`DECISIONS.md\` to match.`, + ); + // Opt-in default plugins are refused via the overlay `server/plugins/config.ts` // (defineAppConfig → the `app` layer getAppConfig() reads). `plugins.disabled` // in agent-native.json is NOT read by the plugin-mount decision, so it must From fe1d1a943db7c157e954c0745a028a65e00e9531 Mon Sep 17 00:00:00 2001 From: Ben Girone Date: Tue, 22 Sep 2026 10:15:04 -0500 Subject: [PATCH 2/5] Move dev-workflow AGENTS.md guidance into DEVELOPING.md AGENTS.md is injected into the runtime chat agent's system prompt on every request and hard-truncated at COMPACT_PROMPT_RESOURCE_MAX_CHARS (6,000 chars); the starter's AGENTS.md was already past that (~6,900 chars) before this branch's own addition pushed it further. Most of the excess was dev-only guidance (choosing an auth landing route, SQL scaffolding pointers, verification cadence, config-vs-env-vars) that only matters to whoever is actively writing source for the app, not to every runtime turn. DEVELOPING.md already exists as the framework's development-mode-only guide and is not injected into the runtime prompt, so move that detail there and leave a short pointer in AGENTS.md. Net result: AGENTS.md drops to ~4,400 chars, comfortably under the cap with room to grow. Co-Authored-By: Claude Sonnet 5 --- .github/starter-patch/apply.mjs | 25 +++++++++++++++++++++---- .github/starter-patch/owned.txt | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/.github/starter-patch/apply.mjs b/.github/starter-patch/apply.mjs index 035c69c..0950e89 100644 --- a/.github/starter-patch/apply.mjs +++ b/.github/starter-patch/apply.mjs @@ -457,6 +457,15 @@ asked for.`, mounted by default; add one only when the user asks.`, ); + // The full dev-workflow guidance (auth landing route, SQL scaffolding, + // verification cadence, config-vs-env-vars) used to live inline in + // AGENTS.md. That file is injected into the runtime chat agent's system + // prompt on every request and hard-truncated at COMPACT_PROMPT_RESOURCE_MAX_CHARS + // (6,000 chars) — content past the cap silently disappears rather than + // being available on demand. DEVELOPING.md is the framework's existing + // convention for development-mode-only guidance (it is not injected into + // the runtime prompt), so the detail moves there and AGENTS.md keeps only + // a pointer. uniqueReplace( path.join(root, "AGENTS.md"), `Before building common workspace or agent UI, read \`agent-native-toolkit\`; read @@ -464,7 +473,14 @@ asked for.`, - Guarded verification: run \`pnpm agent-native:doctor\`; fix findings before done.`, `Before building common workspace or agent UI, read \`agent-native-toolkit\`; read -\`customizing-agent-native\` before adapting shared UI. +\`customizing-agent-native\` before adapting shared UI. Before adding +persistence, auth, or SQL-backed features, read \`DEVELOPING.md\`.`, + ); + + uniqueReplace( + path.join(root, "DEVELOPING.md"), + `See the \`extensions\` skill in \`.agents/skills/extensions/SKILL.md\` for full implementation details.`, + `See the \`extensions\` skill in \`.agents/skills/extensions/SKILL.md\` for full implementation details. ## Data & actions (read these first) @@ -904,11 +920,12 @@ function assertPatched(root) { ); assertContains( root, - "AGENTS.md", + "DEVELOPING.md", "Before enabling authentication, inspect `app/routes`, the app's navigation", ); - assertContains(root, "AGENTS.md", "Never assume `/home` unless that"); - assertContains(root, "AGENTS.md", 'app: { homePath: "/dashboard" },'); + assertContains(root, "DEVELOPING.md", "Never assume `/home` unless that"); + assertContains(root, "DEVELOPING.md", 'app: { homePath: "/dashboard" },'); + assertContains(root, "AGENTS.md", "read `DEVELOPING.md`"); const pluginConfigSrc = readFileSync( path.join(root, "server/plugins/config.ts"), "utf8", diff --git a/.github/starter-patch/owned.txt b/.github/starter-patch/owned.txt index 4b2098b..5e82c7b 100644 --- a/.github/starter-patch/owned.txt +++ b/.github/starter-patch/owned.txt @@ -19,6 +19,7 @@ AGENTS.md CHANGELOG.md CLAUDE.md DESIGN.md +DEVELOPING.md actions/navigate.ts actions/view-screen.ts agent-native.json From 22fd64b57c96ecdd22a577c0ed014bc288b569ec Mon Sep 17 00:00:00 2001 From: Ben Girone Date: Tue, 22 Sep 2026 10:22:02 -0500 Subject: [PATCH 3/5] Point verify-starter-patch's AGENTS.md assertions at DEVELOPING.md CI checks the two hardcoded assertions in verify-starter-patch.yml independently of apply.mjs's own assertPatched(); these still expected the auth-landing-route guidance in AGENTS.md after the previous commit moved it to DEVELOPING.md, so the workflow failed even though the overlay itself applied correctly. Update the workflow's assertions to match, and add a check for the new short pointer left in AGENTS.md. Co-Authored-By: Claude Sonnet 5 --- .github/workflows/verify-starter-patch.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/verify-starter-patch.yml b/.github/workflows/verify-starter-patch.yml index 4643b62..a6002e9 100644 --- a/.github/workflows/verify-starter-patch.yml +++ b/.github/workflows/verify-starter-patch.yml @@ -53,9 +53,10 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$pristine/scripts/migrate-production.ts" grep -q 'must run as its own process' "$pristine/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$pristine/pnpm-workspace.yaml" - grep -q 'Before enabling authentication, inspect `app/routes`' "$pristine/AGENTS.md" - grep -q 'Never assume `/home` unless that' "$pristine/AGENTS.md" - grep -q 'app: { homePath: "/dashboard" }' "$pristine/AGENTS.md" + grep -q 'read `DEVELOPING.md`' "$pristine/AGENTS.md" + grep -q 'Before enabling authentication, inspect `app/routes`' "$pristine/DEVELOPING.md" + grep -q 'Never assume `/home` unless that' "$pristine/DEVELOPING.md" + grep -q 'app: { homePath: "/dashboard" }' "$pristine/DEVELOPING.md" ! grep -q 'homePath' "$pristine/server/plugins/config.ts" assert_idempotent "$pristine" @@ -74,8 +75,9 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$migrated/scripts/migrate-production.ts" grep -q 'must run as its own process' "$migrated/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$migrated/pnpm-workspace.yaml" - grep -q 'Before enabling authentication, inspect `app/routes`' "$migrated/AGENTS.md" - grep -q 'Never assume `/home` unless that' "$migrated/AGENTS.md" - grep -q 'app: { homePath: "/dashboard" }' "$migrated/AGENTS.md" + grep -q 'read `DEVELOPING.md`' "$migrated/AGENTS.md" + grep -q 'Before enabling authentication, inspect `app/routes`' "$migrated/DEVELOPING.md" + grep -q 'Never assume `/home` unless that' "$migrated/DEVELOPING.md" + grep -q 'app: { homePath: "/dashboard" }' "$migrated/DEVELOPING.md" ! grep -q 'homePath' "$migrated/server/plugins/config.ts" assert_idempotent "$migrated" From 30b8c2b6d1a3edba1a9a18cc3cf7894173e95ea0 Mon Sep 17 00:00:00 2001 From: Ben Girone Date: Tue, 22 Sep 2026 15:46:39 -0500 Subject: [PATCH 4/5] Move all dev-only starter-patch guidance out of AGENTS.md into DEVELOPING.md AGENTS.md is injected into the runtime chat agent's system prompt on every request; DEVELOPING.md is not (see COMPACT_PROMPT_RESOURCE_MAX_CHARS in agent-native's prompt-resources.ts, and the loader that reads `instructions.runtime` but never `instructions.development`). Everything this overlay had been patching into AGENTS.md beyond the previous commit's move was actually about editing this app's source code, not about operating the deployed app for end users: the blank-canvas build-additively guidance, the DECISIONS.md check-and-update rule, and the i18n/changelog opt-in note. Move all of it into DEVELOPING.md and collapse AGENTS.md's own patches down to a single pointer sentence in the intro: "See DEVELOPING.md before making any source code change." The agent already reaches for DEVELOPING.md exactly when it's about to edit source, so the pointer does the real work; the content itself no longer needs to survive the 6,000-char runtime prompt cutoff at all. Co-Authored-By: Claude Sonnet 5 --- .github/starter-patch/apply.mjs | 111 ++++++++++----------- .github/workflows/verify-starter-patch.yml | 10 +- 2 files changed, 59 insertions(+), 62 deletions(-) diff --git a/.github/starter-patch/apply.mjs b/.github/starter-patch/apply.mjs index 0950e89..a5aa580 100644 --- a/.github/starter-patch/apply.mjs +++ b/.github/starter-patch/apply.mjs @@ -186,6 +186,11 @@ function assertHomepageShape(root) { } function applyReplacements(root) { + // AGENTS.md is injected into the runtime chat agent's system prompt on every + // request; DEVELOPING.md is not (see COMPACT_PROMPT_RESOURCE_MAX_CHARS in + // agent-native's prompt-resources.ts). Anything here about how to build or + // edit this app's source — not how to operate the running app — belongs in + // DEVELOPING.md instead, reached through this one pointer. uniqueReplace( path.join(root, "AGENTS.md"), `Chat is the minimal chat-first agent-native app. The public root is a marketing @@ -193,13 +198,8 @@ surface; the authenticated chat app starts at \`/home\`. Actions carry the real capabilities, and screens exist only where a workflow needs durable UI around the conversation.`, `This starter ships as a blank Agent-Native app canvas — that describes its -initial state, not necessarily its current one. Before assuming no UI or -brand exists, check \`app/routes/_index.tsx\` and \`app/global.css\`: if they -already contain real content, that content is the current product and its -established brand. Build additively, preserve existing tokens/routes/palette, -and do not re-derive a new visual direction or overwrite shipped UI unless -the user explicitly asks for a redesign. Only treat the canvas as blank when -the files actually show the starter's placeholder content.`, +initial state, not necessarily its current one. See \`DEVELOPING.md\` before +making any source code change.`, ); uniqueReplace( @@ -208,22 +208,6 @@ the files actually show the starter's placeholder content.`, `# App — Agent Guide`, ); - // Fusion's project-shape questionnaire writes `DECISIONS.md` before the - // first build (see ai-services `render-shape-decisions.ts`) and injects a - // one-time instruction to read it into that first prompt. This makes the - // same rule durable across every later session, and adds the update-back - // half: nothing currently rewrites the file when a decision changes in chat. - uniqueReplace( - path.join(root, "AGENTS.md"), - `- Use \`view-screen\` or application state when the active page/selection is - unclear.`, - `- Use \`view-screen\` or application state when the active page/selection is - unclear. -- If \`DECISIONS.md\` exists at the repo root, read it before starting work — - it holds pre-build choices as current requirements. If the user changes one - later in chat, update \`DECISIONS.md\` to match.`, - ); - // Opt-in default plugins are refused via the overlay `server/plugins/config.ts` // (defineAppConfig → the `app` layer getAppConfig() reads). `plugins.disabled` // in agent-native.json is NOT read by the plugin-mount decision, so it must @@ -432,22 +416,6 @@ try { });`, ); - uniqueReplace( - path.join(root, "AGENTS.md"), - `The default app skill surface is intentionally small. Promotion, learning, -translation, changelog, provider, and release workflows are optional; enable -the matching skill only when this app actually uses that workflow.`, - `The default app skill surface is intentionally small. Promotion, learning, -translation, changelog, provider, and release workflows are optional; enable -the matching skill only when this app actually uses that workflow. - -**Do not add internationalization or changelog support unless the user -explicitly asks for them.** This starter ships English-only UI copy inline — -no \`app/i18n/\`, LanguagePicker, \`CHANGELOG.md\`, or What's New surfaces. If the -user requests i18n or changelogs, load the matching skill and add only what they -asked for.`, - ); - uniqueReplace( path.join(root, "AGENTS.md"), `- \`navigation\` describes the current view and selected entity ids. The default @@ -457,31 +425,39 @@ asked for.`, mounted by default; add one only when the user asks.`, ); - // The full dev-workflow guidance (auth landing route, SQL scaffolding, - // verification cadence, config-vs-env-vars) used to live inline in - // AGENTS.md. That file is injected into the runtime chat agent's system - // prompt on every request and hard-truncated at COMPACT_PROMPT_RESOURCE_MAX_CHARS - // (6,000 chars) — content past the cap silently disappears rather than - // being available on demand. DEVELOPING.md is the framework's existing - // convention for development-mode-only guidance (it is not injected into - // the runtime prompt), so the detail moves there and AGENTS.md keeps only - // a pointer. - uniqueReplace( - path.join(root, "AGENTS.md"), - `Before building common workspace or agent UI, read \`agent-native-toolkit\`; read -\`customizing-agent-native\` before adapting shared UI. - -- Guarded verification: run \`pnpm agent-native:doctor\`; fix findings before done.`, - `Before building common workspace or agent UI, read \`agent-native-toolkit\`; read -\`customizing-agent-native\` before adapting shared UI. Before adding -persistence, auth, or SQL-backed features, read \`DEVELOPING.md\`.`, - ); - + // AGENTS.md's one DEVELOPING.md pointer lives in the intro paragraph above; + // everything else this overlay used to add inline to AGENTS.md — the + // blank-canvas build guidance, the DECISIONS.md check, and the + // i18n/changelog opt-in note — moves into DEVELOPING.md below instead. None + // of it helps the runtime agent operate the deployed app; all of it is + // about editing this app's source, which is exactly DEVELOPING.md's job + // (and the one thing AGENTS.md's pointer sends the agent there for). uniqueReplace( path.join(root, "DEVELOPING.md"), `See the \`extensions\` skill in \`.agents/skills/extensions/SKILL.md\` for full implementation details.`, `See the \`extensions\` skill in \`.agents/skills/extensions/SKILL.md\` for full implementation details. +## Preserve existing work + +This starter ships as a blank Agent-Native app canvas — that describes its +initial state, not necessarily its current one. Before assuming no UI or +brand exists, check \`app/routes/_index.tsx\` and \`app/global.css\`: if they +already contain real content, that content is the current product and its +established brand. Build additively, preserve existing tokens/routes/palette, +and do not re-derive a new visual direction or overwrite shipped UI unless +the user explicitly asks for a redesign. Only treat the canvas as blank when +the files actually show the starter's placeholder content. + +If \`DECISIONS.md\` exists at the repo root, read it before starting work — it +holds pre-build choices as current requirements. If the user changes one +later in chat, update \`DECISIONS.md\` to match. + +**Do not add internationalization or changelog support unless the user +explicitly asks for them.** This starter ships English-only UI copy inline — +no \`app/i18n/\`, LanguagePicker, \`CHANGELOG.md\`, or What's New surfaces. If the +user requests i18n or changelogs, load the matching skill and add only what +they asked for. + ## Data & actions (read these first) Add persistence or auth **only when data must survive reload or be shared @@ -925,7 +901,22 @@ function assertPatched(root) { ); assertContains(root, "DEVELOPING.md", "Never assume `/home` unless that"); assertContains(root, "DEVELOPING.md", 'app: { homePath: "/dashboard" },'); - assertContains(root, "AGENTS.md", "read `DEVELOPING.md`"); + assertContains( + root, + "DEVELOPING.md", + "Build additively, preserve existing tokens/routes/palette", + ); + assertContains(root, "DEVELOPING.md", "If `DECISIONS.md` exists at the repo root"); + assertContains( + root, + "DEVELOPING.md", + "Do not add internationalization or changelog support unless the user", + ); + assertContains( + root, + "AGENTS.md", + "See `DEVELOPING.md` before making any source code change.", + ); const pluginConfigSrc = readFileSync( path.join(root, "server/plugins/config.ts"), "utf8", diff --git a/.github/workflows/verify-starter-patch.yml b/.github/workflows/verify-starter-patch.yml index a6002e9..487a42e 100644 --- a/.github/workflows/verify-starter-patch.yml +++ b/.github/workflows/verify-starter-patch.yml @@ -53,10 +53,13 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$pristine/scripts/migrate-production.ts" grep -q 'must run as its own process' "$pristine/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$pristine/pnpm-workspace.yaml" - grep -q 'read `DEVELOPING.md`' "$pristine/AGENTS.md" + grep -q 'See `DEVELOPING.md` before making any source code change.' "$pristine/AGENTS.md" grep -q 'Before enabling authentication, inspect `app/routes`' "$pristine/DEVELOPING.md" grep -q 'Never assume `/home` unless that' "$pristine/DEVELOPING.md" grep -q 'app: { homePath: "/dashboard" }' "$pristine/DEVELOPING.md" + grep -q 'Build additively, preserve existing tokens/routes/palette' "$pristine/DEVELOPING.md" + grep -q 'If `DECISIONS.md` exists at the repo root' "$pristine/DEVELOPING.md" + grep -q 'Do not add internationalization or changelog support unless the user' "$pristine/DEVELOPING.md" ! grep -q 'homePath' "$pristine/server/plugins/config.ts" assert_idempotent "$pristine" @@ -75,9 +78,12 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$migrated/scripts/migrate-production.ts" grep -q 'must run as its own process' "$migrated/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$migrated/pnpm-workspace.yaml" - grep -q 'read `DEVELOPING.md`' "$migrated/AGENTS.md" + grep -q 'See `DEVELOPING.md` before making any source code change.' "$migrated/AGENTS.md" grep -q 'Before enabling authentication, inspect `app/routes`' "$migrated/DEVELOPING.md" grep -q 'Never assume `/home` unless that' "$migrated/DEVELOPING.md" grep -q 'app: { homePath: "/dashboard" }' "$migrated/DEVELOPING.md" + grep -q 'Build additively, preserve existing tokens/routes/palette' "$migrated/DEVELOPING.md" + grep -q 'If `DECISIONS.md` exists at the repo root' "$migrated/DEVELOPING.md" + grep -q 'Do not add internationalization or changelog support unless the user' "$migrated/DEVELOPING.md" ! grep -q 'homePath' "$migrated/server/plugins/config.ts" assert_idempotent "$migrated" From 03d30212ef078cc931166341485f91cc7b70325f Mon Sep 17 00:00:00 2001 From: Ben Girone Date: Tue, 22 Sep 2026 15:47:37 -0500 Subject: [PATCH 5/5] Fix wrapped-line assertion and migrated-tree duplicate-content check The AGENTS.md pointer wraps across two lines at its natural markdown width, so the exact-phrase assertion never matched; check the unwrapped prefix instead. The migrated-tree duplicate-content guard for the i18n/changelog note still pointed at AGENTS.md after the previous commit moved that text to DEVELOPING.md. Co-Authored-By: Claude Sonnet 5 --- .github/starter-patch/apply.mjs | 2 +- .github/workflows/verify-starter-patch.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/starter-patch/apply.mjs b/.github/starter-patch/apply.mjs index a5aa580..5c0cedb 100644 --- a/.github/starter-patch/apply.mjs +++ b/.github/starter-patch/apply.mjs @@ -915,7 +915,7 @@ function assertPatched(root) { assertContains( root, "AGENTS.md", - "See `DEVELOPING.md` before making any source code change.", + "See `DEVELOPING.md` before", ); const pluginConfigSrc = readFileSync( path.join(root, "server/plugins/config.ts"), diff --git a/.github/workflows/verify-starter-patch.yml b/.github/workflows/verify-starter-patch.yml index 487a42e..358077c 100644 --- a/.github/workflows/verify-starter-patch.yml +++ b/.github/workflows/verify-starter-patch.yml @@ -53,7 +53,7 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$pristine/scripts/migrate-production.ts" grep -q 'must run as its own process' "$pristine/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$pristine/pnpm-workspace.yaml" - grep -q 'See `DEVELOPING.md` before making any source code change.' "$pristine/AGENTS.md" + grep -q 'See `DEVELOPING.md` before' "$pristine/AGENTS.md" grep -q 'Before enabling authentication, inspect `app/routes`' "$pristine/DEVELOPING.md" grep -q 'Never assume `/home` unless that' "$pristine/DEVELOPING.md" grep -q 'app: { homePath: "/dashboard" }' "$pristine/DEVELOPING.md" @@ -68,7 +68,7 @@ jobs: git archive origin/main | tar -x -C "$migrated" node "$patch" --root "$migrated" --source-root "$source" test "$(grep -c 'This starter ships as a blank Agent-Native app canvas' "$migrated/AGENTS.md")" = 1 - test "$(grep -c '^\*\*Do not add internationalization or changelog support' "$migrated/AGENTS.md")" = 1 + test "$(grep -c '^\*\*Do not add internationalization or changelog support' "$migrated/DEVELOPING.md")" = 1 grep -q '"db:migrate": "drizzle-kit migrate"' "$migrated/package.json" grep -q '"drizzle-orm": "0.45.2"' "$migrated/package.json" grep -q '"dev": "agent-native dev"' "$migrated/package.json" @@ -78,7 +78,7 @@ jobs: grep -q 'This entrypoint owns framework tables only' "$migrated/scripts/migrate-production.ts" grep -q 'must run as its own process' "$migrated/scripts/migrate-production.ts" grep -q '"@agent-native/\*"' "$migrated/pnpm-workspace.yaml" - grep -q 'See `DEVELOPING.md` before making any source code change.' "$migrated/AGENTS.md" + grep -q 'See `DEVELOPING.md` before' "$migrated/AGENTS.md" grep -q 'Before enabling authentication, inspect `app/routes`' "$migrated/DEVELOPING.md" grep -q 'Never assume `/home` unless that' "$migrated/DEVELOPING.md" grep -q 'app: { homePath: "/dashboard" }' "$migrated/DEVELOPING.md"