diff --git a/.devcontainer/agent-versions.env b/.devcontainer/agent-versions.env index 8a30a51..d5e7016 100644 --- a/.devcontainer/agent-versions.env +++ b/.devcontainer/agent-versions.env @@ -1,11 +1,11 @@ -# Last reviewed together on 2026-08-27. Re-review every pin before each template release. +# Last reviewed together on 2026-08-28. Re-review every pin before each template release. CLAUDE_CODE_VERSION=2.1.226 CODEX_VERSION=0.147.0 -FIRSTDRAFT_CLI_VERSION=0.2.0 +FIRSTDRAFT_CLI_VERSION=0.2.1 # CLI 0.2.x requires staging to serve First Draft API 0.3.x before template promotion. FIRSTDRAFT_CLI_DEFAULT_API_URL=https://firstdraft.com FIRSTDRAFT_STAGING_API_URL=https://staging.firstdraft.com -FIRSTDRAFT_SKILLS_REVISION=2ab23ecb4d0bc6f7a28c6d55de305f25b2f1d893 +FIRSTDRAFT_SKILLS_REVISION=160d33a5a7d9f9b2282729ecfd3b2e24a1123143 FIRSTDRAFT_CLAUDE_SKILL_NAME=create-full-stack-app # Codex namespaces the canonical source checkout with its root plugin manifest. FIRSTDRAFT_CODEX_SKILL_NAME=firstdraft:create-full-stack-app diff --git a/.devcontainer/setup-agents b/.devcontainer/setup-agents index c25fd38..da92697 100755 --- a/.devcontainer/setup-agents +++ b/.devcontainer/setup-agents @@ -128,4 +128,5 @@ firstdraft --version printf '\nDrawing Board setup complete.\n' printf 'Next: paste your staging First Draft token into the `FIRSTDRAFT_API_TOKEN` entry in `.env`.\n' printf 'Then run `claude` or `codex` and describe the app you want.\n' -printf 'A successful Compile returns a fresh private GitHub repository; it does not modify this Drawing Board.\n' +printf 'The ordinary Compile creates `./application`; the agent initializes and verifies it before continuing there.\n' +printf 'Ask explicitly for a private GitHub repository if you want the separate Publication mode.\n' diff --git a/AGENTS.md b/AGENTS.md index 5b38270..4de744c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,9 +19,20 @@ name the Skill or translate the request into a command. Direct-download output has no nested Git repository; run root `script/initialize-application` once before entering it so Git-sensitive application checks cannot resolve to the enclosing Drawing Board repository. Run it before setup or edits; it stops without deleting ignored local state rather than risking that state in the first commit. -- The currently pinned CLI and Skill still Compile by publishing a separate private GitHub repository; they do - not accept `--output` or populate `application/`. The local path and initializer are preparation for a later - coordinated CLI/Skill/pin release. Do not improvise the unreleased command from this repository. +- In this Drawing Board, direct local output is the default completion mode. From the physical workspace root, the + installed Skill runs `bin/firstdraft plan compile --output ./application` after the user approves that exact mode. + The destination must still be absent. On success, run root `script/initialize-application application` before + setup or edits, then `script/application-smoke`; do not manufacture Git metadata or repair generated bytes by hand. +- If `application/` already exists, preserve it. Never delete, overwrite, or move it merely to satisfy the absent-path + precondition. Stop and ask the user whether to continue in the existing application, push its nested `main` to an + approved remote when that repository exists, or preserve it under the Drawing Board's ignored, bind-mounted `tmp/` + before starting a different Compile. Do not use `/tmp`, the container home, or another path that a Codespace + rebuild discards. +- If a Codespaces forwarded-port URL reaches Rails' **Blocked hosts** page, report the known target-owned defect and + stop. Do not edit or clear `config.hosts`, or add host-admission environment variables to the Drawing Board or the + generated application. +- Zero-flag `bin/firstdraft plan compile` is a separate mode for a user who explicitly asks for a private GitHub + repository. Never switch modes to recover from an ambiguous start. Neither mode deploys the application. - Use `bin/firstdraft` for every First Draft command. When the installed Skill shows `firstdraft ...`, pass those same arguments to this repository wrapper. It loads the ignored `.env`, requires staging, and launches the exact pinned standalone CLI for both Claude and Codex. Do not bypass it, call the service with improvised HTTP, or @@ -38,11 +49,15 @@ name the Skill or translate the request into a command. `bin/review-plan-with-claude` or `bin/review-plan-with-codex`. - Never print, log, commit, or request a First Draft token in chat. The local `.env` is agent-readable development credential delivery, not isolation from either agent; `bin/agent-doctor` reports presence only. -- Never request a GitHub personal access token. Publication uses the GitHub account already connected to First Draft - and creates a fresh private repository, not a branch or pull request in this Drawing Board. +- Never request a GitHub personal access token. Direct output creates no Publication or repository. If the user + explicitly selects Publication, it uses the GitHub account already connected to First Draft and creates a fresh + private repository, not a branch or pull request in this Drawing Board. Route an installation-readiness failure + back to First Draft's **Connect GitHub App** flow; do not improvise credentials. - Do not publish or release packages from this repository. -- After Compile succeeds, report the validated private GitHub URL and route the user to the generated repository's - `.firstdraft/submitted-foundation-plan.json` and `.firstdraft/gaps.json`. Continue only in a separate checkout when - the user asks. +- After direct Compile and initialization succeed, report `application/`, its nested initial commit, and its + `.firstdraft/submitted-foundation-plan.json` and `.firstdraft/gaps.json`. State that the parent Drawing Board + ignores this local repository and it has no remote; before the Codespace is deleted, offer to create and push a + remote only with the user's approval. Continue inside that directory. After explicit Publication succeeds, report + the validated private GitHub URL and continue only in a separate checkout when the user asks. When changing the Drawing Board template itself, read `CONTRIBUTING.md` and run `script/check`. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c533221..41f6309 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -18,10 +18,10 @@ A repository created from this template must provide one ready-to-use workspace Selenium services, so an ignored application under `./application` can be developed without a second Codespace. The template does not commit generated application source. `application/` is ignored local output; its Rails source -remains distinct from the Drawing Board even though both use one container. -This is preparatory container plumbing: the currently pinned CLI and Skill still publish a separate private -repository. A later coordinated CLI/Skill/pin packet will activate direct materialization into `application/`. -The accepted cross-repository sequence and its safety boundaries live in +remains distinct from the Drawing Board even though both use one container. The pinned CLI and Skill make direct +materialization available, and Drawing Board's `AGENTS.md` selects the absent `application/` directory as this +template's default completion mode. Zero-flag GitHub Publication remains a separate explicit mode. The accepted +cross-repository sequence and its safety boundaries live in [DIRECT_COMPILATION_PLAN.md](DIRECT_COMPILATION_PLAN.md). ## Repository map @@ -47,6 +47,9 @@ bypass those rules are `.firstdraft/submitted-foundation-plan.json` and `.firstd path is preserved and stops initialization; a future generated ignored file must update this narrow allowlist and its exact-byte fixture in the same coordinated release. Canonical `0644` and `0755` modes are part of the generated artifact contract; a mismatch requires a fresh compile into an absent directory rather than local mode repair. +A mode mismatch aborts initialization before the nested repository exists. Preserve that directory under the +Drawing Board's ignored, bind-mounted `tmp/` before recompiling; never use `/tmp` or the container home, and never +delete or overwrite it to manufacture an absent destination. ## Work on the template @@ -86,4 +89,7 @@ are owned by [firstdraft/firstdraft](https://github.com/firstdraft/firstdraft); Keep [README.md](README.md) focused on the beginner journey. Put maintainer commands and implementation details here, and keep agent-only guardrails in [AGENTS.md](AGENTS.md). If a workflow change affects what a tester must do, update -the README and verify the complete template-to-generated-repository journey before landing it. +the README and verify the affected journey before landing it: template-to-`application/` for direct mode, or the +separate-repository journey for Publication. [DIRECT_COMPILATION_PLAN.md](DIRECT_COMPILATION_PLAN.md) owns the +current direct-journey acceptance steps and every explicitly unfinished step; do not call that journey complete +until those steps are observed. diff --git a/DIRECT_COMPILATION_PLAN.md b/DIRECT_COMPILATION_PLAN.md index e769c2d..f0c6141 100644 --- a/DIRECT_COMPILATION_PLAN.md +++ b/DIRECT_COMPILATION_PLAN.md @@ -116,6 +116,20 @@ their owning tools rather than copying them. Drawing Board continues to install so plugin publication or catalog promotion is not required for this packet. CLI `latest`, plugin publication, and catalog promotion remain separate release choices. +The released packet-2.5 inputs observed on 2026-08-28 are: + +- CLI `0.2.1`, source/tag commit `d38ef3e54a6476b3a91f22a17fe7bd47aa6d6d68`, tree + `e62ee3ff1fb6d188c5d2c5a6e5e0efd50b40245f`, published under npm's `next` tag while `latest` remains `0.1.0`; +- Skills `0.2.1` at `160d33a5a7d9f9b2282729ecfd3b2e24a1123143`, tree + `6f3db12c017e884d8b14c66f7d82e64229ec2073`, installed by Drawing Board from source; and +- staging advertising First Draft API contract `0.3.0`. + +Drawing Board now pins that CLI/Skills pair and teaches direct `./application` output as its ordinary path. The +candidate plugin `0.2.1` digest is `36e3e80db76d4af6c2af96d87fe42e00b944aab01e16584e6eb5149dc3f196b1`, but this source-pin packet does not publish +plugin bytes, move a catalog, or move npm's `latest` dist-tag. The `next` tag moved to CLI `0.2.1` in step 3. Packet +3 owns the observed non-prebuilt journey rather than inferring it from these compatible release coordinates; the +result below also preserves what that journey did not yet prove. + ## Packet 3: one real non-prebuilt Codespace journey After packets 1 and 2 are integrated into a coherent candidate tuple, confirm that staging serves the API contract @@ -136,6 +150,49 @@ required by that tuple, then exercise a newly created Drawing Board Codespace wi 7. Ask the same agent to explain one Plan decision from the retained design context and make one bounded application change that follows it, then run a focused generated-app check. +### Observed Packet 3 boundary on 2026-08-28 + +A fresh private repository and Codespace exercised the exact Drawing Board candidate without a prebuild: + +- Drawing Board source `f93d54a2a55ca7d06abe072424092b1dd0544117`, tree + `ade2a7079299d84cfd746c241aff905b3cd0115b`, was copied into one parentless test-repository commit + `fd73196251e341893f8e0496e4d1ba6765c89f49` with the same tree. +- One `basicLinux32gb` East US Codespace reached `Available` 404.5 seconds after its create request. Its runtime + reported CLI `0.2.1`, Skills `160d33a5a7d9f9b2282729ecfd3b2e24a1123143`, Claude Code `2.1.226`, and Codex + `0.147.0`; the Dev Container smoke and direct-output capability checks passed. +- The approved Neighborhood Guide Plan SHA-256 was + `1e88f919436d779176abd115f79f84293d4ea4579d21cc07bdc64db3b1a2a962`. Analysis + `01a04a08-e38a-7708-accb-d2980cfc0c7f` returned a valid zero-record GapSet with SHA-256 + `e1d40a25d442b18380882e644ff1e4d5a6191159eb3b0cdaff258f20f7ad3fc7` before the owner approved direct mode. +- Exactly one direct Compile started. Compilation `01a04a0d-3484-7e29-b743-0c77b96db063` succeeded with artifact + SHA-256 `0f26014b38d64816ce4b7934e969ce9a3db715a96f3789df609a45b81bf35188`, 479,770 artifact bytes, + 168 output files, and manifest SHA-256 + `08269fa09226d41d89894dbef1f0a26cbd51c7fc47b7ca81d5085f44c8480d1c`. The emitted submitted Plan and + GapSet bytes matched the approved inputs, and the new directory had no Git metadata. +- The Project's Publication route returned exact `404 publication_not_found` before and after Compile. The owner's + 551-repository GitHub inventory was byte-identical before and after, so the direct path created no Publication or + generated repository. +- `script/initialize-application application` produced parentless commit + `3f763a84ceab6d7f3564f382bc77cce267a528f1`, tree `11a52026505434bd3242c9cab94d49ed68638681`, on + nested `main`. `script/application-smoke` passed setup, PostgreSQL 18.6, readiness, 56 Rails tests with 209 + assertions, seven system tests with 34 assertions, and the complete clean generated CI in 69.22 seconds under + Ruby 4.0.5 and Node 24.18.0. +- A real browser rendered `It works. · Neighborhood Guide` and the empty `Places · Neighborhood Guide` index + through an authenticated localhost forward to the same Codespace process. The ordinary private Codespaces + `*.app.github.dev` URL instead reached Rails' blocked-host page. The generated Rails development configuration did + not admit that exact Codespaces host; broadening the Drawing Board container environment would not preserve Rails' + exact host boundary. This is a generated Foundation target defect, not a successful ordinary forwarded-port + observation, and requires a target-owned correction before the colleague Codespaces browser journey is complete. +- The single task token was revoked after proof and the exact credential then received `401 authentication_required`. + The revoked value was removed from the Codespace, and the Codespace stop was requested. + +This run proved agent and Skill installation/discovery, but neither installed agent was signed in inside the +Codespace. The active external agent drove the exact Skill sequence over SSH, loaded a previously reviewed Plan, +and obtained fresh owner approval of its exact Plan, GapSet, and direct effect. It did not perform the new +in-Codespace conversational authoring pass, boot the browser process through step 6's `bin/dev` wrapper, or perform +step 7's retained-context explanation and bounded source change. Those remain explicit acceptance work rather than +being inferred from installation, `bin/rails server`, or Compilation success. + Retain exact Service, CLI, Drawing Board, Plan, GapSet, artifact, generated tree, nested initial commit, container, database, smoke output, and browser coordinates. If the Compilation start has an unknown outcome without a retained identity, abort the qualification, preserve its Project/request/response/timing evidence, and ask a Service operator diff --git a/README.md b/README.md index a2de57d..3711581 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Build an app with First Draft This repository is a workspace for planning an app with Claude or Codex. You describe what you want, your agent asks -questions, and First Draft creates a new private GitHub repository containing a working Rails application. +questions, and First Draft creates a working Rails application in the `application` folder of this workspace. You do not need to install programming tools on your computer. The GitHub Codespace created from this template contains everything the agent needs. @@ -14,8 +14,7 @@ You will need: - access to ; and - a Claude or Codex account. -Use the same personal GitHub account throughout the process. That account will own the generated application -repository. +Use the same personal GitHub account for the Drawing Board, Codespace, and First Draft sign-in. ## 1. Create your Drawing Board @@ -23,7 +22,8 @@ repository. 2. Select **Use this template**, then **Create a new repository**. 3. Give the repository a name for your app idea and select **Create repository**. -This repository is your Drawing Board. The generated application will be created later in a different repository. +This repository is your Drawing Board. The generated application will appear later in its ignored `application` +folder, separate from the Drawing Board source. ## 2. Open the Codespace @@ -34,18 +34,19 @@ This repository is your Drawing Board. The generated application will be created The first setup may take a few minutes. Leave the browser tab open while it finishes. -## 3. Connect First Draft to GitHub +## 3. Sign in to First Draft 1. Open in another browser tab. 2. Select **Sign in with GitHub**. -3. On the Projects page, select **Connect GitHub App**. -4. Follow GitHub's prompts to install the App on your personal account. +3. Leave that browser tab open so you can create the token in the next step. -If GitHub asks which repositories the App may access, **Only select repositories** is sufficient. GitHub -automatically gives the App access to repositories it creates. +This sign-in is enough for the ordinary in-workspace path. If you want First Draft to create a separate private +GitHub repository instead, also select **Connect GitHub App** and follow GitHub's prompts. **Only select +repositories** is sufficient; GitHub automatically gives the App access to repositories it creates. -The requested repository permissions let First Draft create the private repository, write the application source, -and include its GitHub Actions workflow. They do not give the App access to unselected existing repositories. +For that optional Publication path, the requested permissions let First Draft create the private repository, write +the application source, and include its GitHub Actions workflow. They do not give the App access to unselected +existing repositories. ## 4. Add your First Draft token @@ -76,25 +77,44 @@ sign-in prompts that appear. Then describe the app in ordinary language. For exa Answer the agent's follow-up questions. It will turn your answers into a Foundation Plan, ask you to review the important choices, and show you anything the generated application will leave for later work. -When the Plan looks right, approve the Compile. First Draft will create a new private GitHub repository and the -agent will give you its URL. +When the Plan looks right, approve the in-workspace Compile. First Draft will put the generated application in +`application`, and the agent will initialize and verify it before continuing there. + +If you want a separate private GitHub repository instead, say so before approving the Compile. The agent will use +the distinct Publication mode and give you that repository's URL. This mode requires the **Connect GitHub App** step +from §3. Neither mode deploys the application. Codex may ask permission for an exact `bin/firstdraft ...` command to contact `staging.firstdraft.com`. Approve that command; do not grant unrelated network access. -## 6. Open your application +## 6. Continue in your application + +For the ordinary in-workspace path, the agent runs these Drawing Board commands after Compile: -Open the new repository from the URL the agent provides. This is the Rails application you will continue working -on; the Drawing Board remains a separate planning workspace. +```sh +script/initialize-application application +script/application-smoke +``` -The generated repository includes: +The first command gives the generated source its own initial Git history before setup or edits. The second verifies +the generated application without changing its source. Continue working from the `application` folder; the Drawing +Board root remains the planning workspace. The generated application's README owns its normal `bin/dev` command, +but the browser-only Codespaces preview route is not qualified yet, as described under Troubleshooting. + +That nested repository starts with no remote. The parent Drawing Board ignores `application`, so pushing the Drawing +Board does not back up the generated source, and deleting the Codespace can remove its only copy. Before deleting the +Codespace, ask your agent to help create an approved remote and push the nested `main`. If you want First Draft to +create the separate private repository for you, complete **Connect GitHub App** in §3 and choose Publication before +Compile instead. + +The generated application includes: - runnable application source and tests; - the exact submitted Foundation Plan at `.firstdraft/submitted-foundation-plan.json`; and - the reviewed list of remaining work at `.firstdraft/gaps.json`. -Create a Codespace in the generated repository and follow its README to run the application and continue building -it with your agent. +If you explicitly chose Publication, open the private repository from the URL the agent provides. Create a +Codespace there and follow its README instead; the original Drawing Board remains a separate planning workspace. ## Troubleshooting @@ -116,7 +136,11 @@ bin/agent-doctor The doctor reports whether the token is present without showing it. If it reports an `.env` permissions problem, run `chmod 600 .env` and try again. -First Draft is currently an internal preview. Use it for test projects. Compile creates a private GitHub repository; -it does not deploy the application. +The current generated Foundation can show Rails' **Blocked hosts** page at an ordinary Codespaces forwarded-port +URL. Stop and tell your agent if that happens; do not disable Rails' host checks. The target needs a generated-app +correction before that browser route is qualified. + +First Draft is currently an internal preview. Use it for test projects. The ordinary Compile creates only the local +`application` directory; explicit Publication creates a private GitHub repository. Neither deploys the application. Maintaining this template? Read [CONTRIBUTING.md](CONTRIBUTING.md). diff --git a/script/check-firstdraft-wrapper.mjs b/script/check-firstdraft-wrapper.mjs index 84d0442..d0805b6 100644 --- a/script/check-firstdraft-wrapper.mjs +++ b/script/check-firstdraft-wrapper.mjs @@ -27,7 +27,7 @@ const fs = require("node:fs"); const arguments_ = process.argv.slice(2); if (arguments_.length === 1 && arguments_[0] === "--version") { process.stdout.write("firstdraft " + - (process.env.FIRSTDRAFT_TEST_CLI_VERSION ?? "0.2.0") + "\\n"); + (process.env.FIRSTDRAFT_TEST_CLI_VERSION ?? "0.2.1") + "\\n"); if (process.env.FIRSTDRAFT_TEST_CLI_NOTICE) { process.stderr.write("A benign version notice.\\n"); } @@ -164,7 +164,7 @@ fs.writeFileSync(process.env.FIRSTDRAFT_TEST_OUTPUT, JSON.stringify({ root: testRepository, stdio: "ignore", }), - /standalone First Draft CLI must be exactly 0\.2\.0/, + /standalone First Draft CLI must be exactly 0\.2\.1/, ); } finally { fs.rmSync(temporaryRoot, {force: true, recursive: true}); diff --git a/script/devcontainer-smoke b/script/devcontainer-smoke index 686f49b..5193074 100755 --- a/script/devcontainer-smoke +++ b/script/devcontainer-smoke @@ -48,6 +48,9 @@ bin/agent-doctor --installation-only claude --effort high --permission-mode plan --allowed-tools "Read,Glob,Grep,Skill" --version >/dev/null codex --sandbox read-only --ask-for-approval never exec --help >/dev/null +compile_help="$(firstdraft plan compile --help)" +grep -F -- "--output" <<<"$compile_help" >/dev/null + test "$(command -v firstdraft)" = "$PWD/bin/firstdraft" test "$(command -v ruby)" = "$HOME/.local/share/mise/shims/ruby" test ! -L .env @@ -74,6 +77,7 @@ for skill_path in "$claude_skill_path" "$codex_skill_path"; do test "$(git -C "$skill_path" rev-parse HEAD)" = "$FIRSTDRAFT_SKILLS_REVISION" test "$(cd "$skill_path" && pwd -P)" = "$expected_skill_path" done +grep -Fq "firstdraft_cli plan compile --output ./application" "$codex_skill_path/SKILL.md" prompt_input="$(codex debug prompt-input "Use the create-full-stack-app Skill.")" skill_target="$(cd "$codex_skill_path" && pwd -P)/SKILL.md"