butterbase-ai/journey-submit
Use 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 calls prep_and_submit_hackathon_entry. Writes the receipt to docs/butterbase/05-submission.md.
npx skills add https://github.com/butterbase-ai/butterbase-skills --skill journey-submit
Stage 5 (final) of the guided journey. Resolve the active hackathon, confirm fields, submit.
journey when current_stage: submit and hackathon_mode: true./butterbase-skills:submit."submit is disabled outside hackathon mode") if hackathon_mode: false.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.
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.
docs/butterbase/01-idea.md — title / tagline candidates.docs/butterbase/02-plan.md — feature list.docs/butterbase/04-build-log.md — what actually shipped.docs/butterbase/00-state.md — app_id, deployed_url.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.
// First, ask the user: "Do you have a submission code from the organizer? (paste it, or 'no')"
// If yes, pass it. If no, omit it.
{
"tool": "prep_and_submit_hackathon_entry",
"arguments": {
"action": "prep",
"submission_code": "<optional, from user>"
}
}
The response shape is:
{
"matched": null | { "slug", "name", "submission_deadline", "ends_at", "field_schema": { "fields": [...] } },
"match_reason": null | "submission_code" | "already_bound" | "single_open",
"open_hackathons": [{ "slug", "name", "starts_at", "ends_at", "submission_deadline" }, ...],
"next_call": { ... } // present only when matched is non-null
}
Branch on the result:
| matched | open_hackathons.length | Action |
|---|---|---|
| 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"). |
| null | 0 | No hackathon is currently open for submissions. Tell the user, stop, and do not tick submit. |
| 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. |
| 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. |
> 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.
matched.field_schema.fields is the authoritative list of fields for *this* hackathon. Walk every field in order. For each:
label (not key) and description.is_url: true or type: "url") for the deployed app → deployed_url from 00-state.md.01-idea.md.01-idea.md + must-haves.required: false.options-typed fields, present the allowed choices verbatim.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.
Show the assembled data object back to the user verbatim and ask: "Submit now? (yes/no)". On yes:
{
"tool": "prep_and_submit_hackathon_entry",
"arguments": {
"action": "submit",
"hackathon_slug": "<matched.slug from prep — REQUIRED when multiple are open>",
"app_id": "<app_id from 00-state.md — strongly recommended, unlocks +50 scoring points>",
"submission_code": "<same code passed to prep, if any — required on first submission>",
"data": { /* user-confirmed values keyed by field.key */ }
}
}
> Always pass hackathon_slug = matched.slug from prep. Without it, submit re-resolves and may target a different hackathon if more than one is open.
> Always pass app_id — scoring awards up to 50 points for Butterbase usage on that specific app.
Capture the response (submission.id, submission.version, submission.updated_at, participant_created) and write docs/butterbase/05-submission.md:
# Submission
- submitted_at: <submission.updated_at>
- submission_id: <submission.id>
- version: <submission.version>
- hackathon_slug: <submission.hackathon_slug>
- hackathon_name: <matched.name>
- app_id: <submission.app_id>
- participant_created: <true|false>
## Fields submitted
<one bullet per field: label → value>
Tick - [x] submit in 00-state.md, set current_stage: done. Print a one-line success to the user including the hackathon name and submission id.
prep_and_submit_hackathon_entry (action: "prep" then "submit").docs/butterbase/05-submission.md.action: "prep" and calling submit directly with a hardcoded field list.open_hackathons on the prep response.matched.field_schema.fields.hackathon_slug from prep (can re-resolve to the wrong hackathon).app_id when one exists (forfeits up to 50 scoring points).yes from the user on the assembled payload.Take butterbase-ai/journey-submit from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.