From 3d3b73d48c49b351505030d6194bfe574b8e1f45 Mon Sep 17 00:00:00 2001 From: Raghu Betina Date: Sun, 4 Oct 2026 17:47:48 -0500 Subject: [PATCH] Describe generated photo and file uploads The service's image-uploads Compiler release imports image and attachment Fields and generates Active Storage uploads on Cloudinary. The Plan reference still said those Fields are skipped, so an agent would promise a photo-less app. List both types as imported, say what they generate and what stays a gap, and keep the CLOUDINARY_URL instruction 0.8.3 added: setup works without it, and the first upload names it in a KeyError. The damage photo eval now expects a child Entity with one image Field instead of skipped gaps. Packaged bytes changed, so this targets plugin 0.8.4; it should publish only after that service release is deployed. --- CHANGELOG.md | 10 ++++++++ evals/create-full-stack-app/cases.json | 2 +- package-lock.json | 4 ++-- package.json | 2 +- .../claude-plugin/.claude-plugin/plugin.json | 2 +- packages/claude-plugin/package.template.json | 2 +- release/compatibility.json | 4 ++-- skills/create-full-stack-app/SKILL.md | 2 +- .../references/diagnostics-and-recovery.md | 2 +- .../references/foundation-plan-023.md | 23 +++++++++++-------- 10 files changed, 34 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfcd2e4..4ca61b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,16 @@ Entries are newest first. Keep their headings stable. Publish material correctio new entries so readers who advanced their checkpoint see them. Entries explain what changed, why, when it applies, and any useful small example or verification; they need not reproduce commit logs. +## 2026-10-04: Photo and file uploads + +**Skills — released in plugin 0.8.4.** The authoring reference now says that `image` and `attachment` Fields +compile to Active Storage uploads instead of being skipped, what they generate, and what stays a gap. Generated apps +store uploads on Cloudinary, so the Skill tells the user to create a Cloudinary account and set `CLOUDINARY_URL` in +`.env.development.local` and in Render; setup works without it, and the first upload raises a `KeyError` naming it. +It applies once the First Draft service runs Compiler release +`foundation-plan-rails/compiler-application-2026-10-04-image-uploads` or later; until then the GapSet still lists +these Fields as skipped. + ## 2026-10-03: An interview that asks your level first **Skills — released in plugin 0.8.3.** The Skill's interview now follows one order. The agent clarifies your idea, diff --git a/evals/create-full-stack-app/cases.json b/evals/create-full-stack-app/cases.json index c626833..5046173 100644 --- a/evals/create-full-stack-app/cases.json +++ b/evals/create-full-stack-app/cases.json @@ -316,7 +316,7 @@ "expectations": [ "Uses the supplied document without a redundant artifact invitation and models item-level return facts independently of the whole loan.", "Does not turn four printed photo boxes into four fixed Fields or infer a fixed attachment limit.", - "Preserves attachment intent as structured meaning whose image or attachment Fields become service-support gaps skipped at import, separate from outside-grammar media/import work in notes; does not encode file paths as supported uploaded seed values.", + "Preserves attachment intent as structured meaning, such as a child Entity with one image Field per damage photo, separate from outside-grammar media/import work in notes; does not encode file paths as supported uploaded seed values.", "Does not retain private filled-in content in Plan, notes, seed, archive or repository." ], "artifacts": [ diff --git a/package-lock.json b/package-lock.json index 29df527..73f0ea7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@firstdraft/skills", - "version": "0.8.3", + "version": "0.8.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@firstdraft/skills", - "version": "0.8.3", + "version": "0.8.4", "license": "MIT", "devDependencies": { "ajv": "8.20.0" diff --git a/package.json b/package.json index 200f2aa..0b27b2e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@firstdraft/skills", - "version": "0.8.3", + "version": "0.8.4", "description": "Portable Agent Skills for First Draft", "license": "MIT", "private": true, diff --git a/packages/claude-plugin/.claude-plugin/plugin.json b/packages/claude-plugin/.claude-plugin/plugin.json index ec81d0c..1af1c19 100644 --- a/packages/claude-plugin/.claude-plugin/plugin.json +++ b/packages/claude-plugin/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "firstdraft", "displayName": "First Draft", - "version": "0.8.3", + "version": "0.8.4", "description": "Author a Foundation Plan and compile a bounded Rails, iPhone, and Android application", "author": { "name": "First Draft", diff --git a/packages/claude-plugin/package.template.json b/packages/claude-plugin/package.template.json index f906036..fc58e5b 100644 --- a/packages/claude-plugin/package.template.json +++ b/packages/claude-plugin/package.template.json @@ -1,6 +1,6 @@ { "name": "@firstdraft.com/claude-code", - "version": "0.8.3", + "version": "0.8.4", "description": "First Draft Foundation Plan authoring and Compilation for Claude Code and Codex", "license": "MIT", "type": "module", diff --git a/release/compatibility.json b/release/compatibility.json index 4fe95b6..a4a0d1a 100644 --- a/release/compatibility.json +++ b/release/compatibility.json @@ -1,10 +1,10 @@ { "format": "firstdraft.release-compatibility/1", "component": "skills", - "version": "0.8.3", + "version": "0.8.4", "plugin_source": { "package": "@firstdraft.com/claude-code", - "tarball_sha256": "f5639a83ac299dde1748635a16edff5148f1d8450003ba5cd6ce9b8611c27946" + "tarball_sha256": "0048a347a60dd1dc78bb4d7037720585cf10a851fd38026c271cfdefe4371b57" }, "requires": { "api_contract": [ diff --git a/skills/create-full-stack-app/SKILL.md b/skills/create-full-stack-app/SKILL.md index 5174743..313cc3e 100644 --- a/skills/create-full-stack-app/SKILL.md +++ b/skills/create-full-stack-app/SKILL.md @@ -23,7 +23,7 @@ explicit handoff. Follow [writing notes](references/modeling-guide.md#retain-imp ## Current boundary -Targets plugin 0.8.3, CLI 0.8.1, API 0.7, Plan 0.23; catalog selection is separate. +Targets plugin 0.8.4, CLI 0.8.1, API 0.7, Plan 0.23; catalog selection is separate. - Bounded generation includes Web Accounts/Policies/Scaffolds, development data, and selected iPhone/Android clients. [Appearance](references/foundation-plan-023.md#application-and-clients) controls theme and native colors, diff --git a/skills/create-full-stack-app/references/diagnostics-and-recovery.md b/skills/create-full-stack-app/references/diagnostics-and-recovery.md index e4fc146..fe87020 100644 --- a/skills/create-full-stack-app/references/diagnostics-and-recovery.md +++ b/skills/create-full-stack-app/references/diagnostics-and-recovery.md @@ -9,7 +9,7 @@ interleaved output fail closed. Branch on the object's stable `error` and struct human-readable `detail` or broad process exit status. This plugin bundles `@firstdraft.com/cli@0.8.1`. Its exact reviewed revision and runtime digest are owned by -[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.3/script/cli-contract/config.mjs) +[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.4/script/cli-contract/config.mjs) at this plugin's protected release tag. Check the command surface rather than assuming the version alone establishes compatibility. These source checks do not prove plugin/catalog publication, service authentication, staging compatibility, or a complete user journey. diff --git a/skills/create-full-stack-app/references/foundation-plan-023.md b/skills/create-full-stack-app/references/foundation-plan-023.md index ee310ac..43d96a2 100644 --- a/skills/create-full-stack-app/references/foundation-plan-023.md +++ b/skills/create-full-stack-app/references/foundation-plan-023.md @@ -82,7 +82,7 @@ The bundled schema was copied byte-for-byte from release or execution evidence. This plugin's bundled CLI and pinned contract check use the exact reviewed CLI revision and runtime digest in -[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.3/script/cli-contract/config.mjs) +[the CLI contract configuration](https://github.com/firstdraft/skills/blob/claude-v0.8.4/script/cli-contract/config.mjs) at this plugin's protected release tag, as contract provenance rather than release or execution evidence. The CLI exposes `generate uuid`, `generate application-key`, `plan init`, `plan push`, `plan status`, local `plan compile` (equivalent to `--output .`), explicit `plan compile --github`, @@ -326,11 +326,13 @@ descriptor terminates in a required emitted scalar or system Field. It preloads The whole-graph analyzer rejects an optional Field descriptor; multi-target, longer-chain, optional-source, cyclic, or otherwise unsupported Association descriptors remain exact gaps. A Field may use these types: +- `attachment` - `boolean` - `date` - `datetime` - `decimal` - `enum` +- `image` - `integer` - `language_code` - `long_text` @@ -354,14 +356,17 @@ query `status_active` when the stored state is `active`. Check an affected appli state; no generated workaround or namespace-based scope suppression is supplied. With `no_direct_assignment: true`, a scoped builder can also raise even for the initial state. Use ordinary creation followed by the named event when a transition is intended; constructing its destination state directly would bypass the event's effects. -`attachment` and `image` are schema-valid -Field types, but they are skipped from the admitted graph and recorded as service-support gaps; they cannot reach -the current Compiler. Active Storage and image-delivery prose describes target direction, not emitted support. -Keep requested image and attachment Fields in the Plan either way. When a Compiler generates them, so that the -matching GapSet no longer reports the Field skipped, it stores files with Active Storage on Cloudinary. Then tell -the user to sign up for Cloudinary and set `CLOUDINARY_URL` from its dashboard in `.env.development.local` for -local use and in the Render environment for the deployed app. The user sets it; never ask for, print, or commit -its value. +An `attachment` or `image` Field compiles to Active Storage `has_one_attached`, with a presence validation when +required, a Scaffold file input (images accept `image/*`), and an image or download link on show pages and list rows. +Development seeds attach a placeholder file on local disk to each required upload; development data cannot supply +upload bytes. A required upload on the Account Entity has no signup control, so signup stays a partial gap. An older +service may still report these Fields as skipped in the GapSet; keep them in the Plan either way. +Generated apps store uploads on Cloudinary in development and production. Tell the user to sign up for Cloudinary +and set `CLOUDINARY_URL` from its dashboard in `.env.development.local` for local use and in the Render environment +for the deployed app; setup works without it, but the first upload raises a `KeyError` naming it. The user sets +it; never ask for, print, or commit its value. Uploaded files have public URLs. Type and size limits, several files +per Field, direct uploads, and protected delivery are not generated; model several photos as a child Entity with +one `image` Field. ### Field capability matrix