$npx -y skills add butterbase-ai/butterbase-skills --skill journey-submitUse as the final stage of the Butterbase journey when hackathon_mode is true and journey-deploy has passed. Resolves which hackathon to submit to (asking the user when multiple are open), walks every field in the hackathon's returned field_schema with the user one at a time, then
| 1 | # Journey: Hackathon submission |
| 2 | |
| 3 | Stage 5 (final) of the guided journey. Resolve the active hackathon, confirm fields, submit. |
| 4 | |
| 5 | ## When to use |
| 6 | |
| 7 | - Dispatched by `journey` when `current_stage: submit` and `hackathon_mode: true`. |
| 8 | - Directly via `/butterbase-skills:submit`. |
| 9 | - No-op (returns with `"submit is disabled outside hackathon mode"`) if `hackathon_mode: false`. |
| 10 | |
| 11 | ## Preflight |
| 12 | |
| 13 | If `docs/butterbase/03-preflight.md` is missing, older than 24 hours, or `00-state.md` has `app_id: null`, invoke `butterbase-skills:journey-preflight` first. Wait for it to return successfully before proceeding. |
| 14 | |
| 15 | Additionally: refuse to run unless `deploy` is ticked in `00-state.md`. If it is not, tell the user to run `/butterbase-skills:journey-deploy` first. |
| 16 | |
| 17 | ## Inputs |
| 18 | |
| 19 | - `docs/butterbase/01-idea.md` — title / tagline candidates. |
| 20 | - `docs/butterbase/02-plan.md` — feature list. |
| 21 | - `docs/butterbase/04-build-log.md` — what actually shipped. |
| 22 | - `docs/butterbase/00-state.md` — `app_id`, `deployed_url`. |
| 23 | |
| 24 | ## Procedure |
| 25 | |
| 26 | ### Step 1 — Prep (resolve which hackathon) |
| 27 | |
| 28 | Always start with `action: "prep"`. Do **not** assume there is exactly one hackathon, and do **not** invent a field schema from prior context — the platform owns the schema and it varies per hackathon. |
| 29 | |
| 30 | ```jsonc |
| 31 | // First, ask the user: "Do you have a submission code from the organizer? (paste it, or 'no')" |
| 32 | // If yes, pass it. If no, omit it. |
| 33 | { |
| 34 | "tool": "prep_and_submit_hackathon_entry", |
| 35 | "arguments": { |
| 36 | "action": "prep", |
| 37 | "submission_code": "<optional, from user>" |
| 38 | } |
| 39 | } |
| 40 | ``` |
| 41 | |
| 42 | The response shape is: |
| 43 | |
| 44 | ```jsonc |
| 45 | { |
| 46 | "matched": null | { "slug", "name", "submission_deadline", "ends_at", "field_schema": { "fields": [...] } }, |
| 47 | "match_reason": null | "submission_code" | "already_bound" | "single_open", |
| 48 | "open_hackathons": [{ "slug", "name", "starts_at", "ends_at", "submission_deadline" }, ...], |
| 49 | "next_call": { ... } // present only when matched is non-null |
| 50 | } |
| 51 | ``` |
| 52 | |
| 53 | Branch on the result: |
| 54 | |
| 55 | | `matched` | `open_hackathons.length` | Action | |
| 56 | |---|---|---| |
| 57 | | non-null | any | Resolved — continue to Step 2 with `matched.field_schema`. Mention `match_reason` to the user ("Resolved via your submission code", "You're already a participant in X", "Only one hackathon is open: X"). | |
| 58 | | null | `0` | No hackathon is currently open for submissions. Tell the user, **stop**, and do not tick `submit`. | |
| 59 | | null | `1` | One hackathon is open but the user isn't bound and didn't supply a code. Ask: `"The only open hackathon is '<name>' (deadline <submission_deadline>). Submit to this one? If so, paste the submission_code the organizer gave you."` Re-run prep with the code. | |
| 60 | | null | `≥ 2` | **Multiple open hackathons — ask the user which one.** Present the list (name, slug, deadline) and ask: `"Which hackathon are you submitting to? Paste its submission_code."` Re-run prep with the code. Never guess. | |
| 61 | |
| 62 | > Anti-pattern: do not re-run prep in a loop hoping it resolves — it won't until the user provides a `submission_code`. One question, then re-prep. |
| 63 | |
| 64 | ### Step 2 — Walk the returned field_schema with the user |
| 65 | |
| 66 | `matched.field_schema.fields` is the **authoritative** list of fields for *this* hackathon. Walk every field in order. For each: |
| 67 | |
| 68 | 1. Show the user the field's `label` (not `key`) and `description`. |
| 69 | 2. Propose a value drawn from journey artifacts where obvious: |
| 70 | - URL-typed fields (`is_url: true` or `type: "url"`) for the deployed app → `deployed_url` from `00-state.md`. |
| 71 | - Project name / title field → top candidate from `01-idea.md`. |
| 72 | - Description / summary field → one-liner from `01-idea.md` + must-haves. |
| 73 | - Repo URL → ask, no default. |
| 74 | - Team info → ask, no default. |
| 75 | - Demo video → ask, allow skip if `required: false`. |
| 76 | - Anything else → ask. |
| 77 | 3. Confirm one at a time. Do not batch. Required fields must have a non-empty value before moving on. |
| 78 | 4. For `options`-typed fields, present the allowed choices verbatim. |
| 79 | |
| 80 | Use `next_call.arguments.data` from the prep response as the literal template — it has one key per field with a placeholder string. Replace each placeholder with the confirmed value. |
| 81 | |
| 82 | ### Step 3 — Submit |
| 83 | |
| 84 | Show the assembled `data` object back to the user verbatim and ask: `"Submit now? (yes/no)"`. On `yes`: |
| 85 | |
| 86 | ```jsonc |
| 87 | { |
| 88 | "tool": "prep_and_submit_hackathon_entry", |
| 89 | "arguments": { |
| 90 | "action": "submit", |
| 91 | "hackathon_slug": "<matched.slug from prep — REQUIRED when multiple are open>", |
| 92 | "app_id": "<app_id from 00-state.md — strongly recommended, unlocks +50 scoring points>", |
| 93 | "submission_code": "<same code passed to prep, if any — required on first submissio |