Start here: this week

The Gecko capstone, step by step

This is the long version of the Gecko capstone: every step from an empty folder to Friday's six minutes, in the order you do them. The code lives in Gecko-Academy/Dev3Pack-Gecko-Capstone-Project; its README is the reference, and this page is the path through it.

The whole path, in one list:

It is separate from the final assignment. The capstone is judged at the presentation; the certificate comes only from the final assignment.

1. What you are building

You ask once, in plain words: "one espresso". Your buyer agent:

  1. reads the menu through Gecko (list_stores), and decides there;
  2. pins what was asked to a file in intents/, before any bytes exist;
  3. has Gecko prepare the purchase as unsigned bytes (prepare_purchase);
  4. checks seven fields of those bytes against the pin: program, store, product, price, mint, quantity, destination;
  5. signs only if every field agrees, with a key Gecko never sees;
  6. has Gecko verify the signed bytes, then submits them;
  7. writes one receipt, read from the ledger, that says what moved.

When a field disagrees, it stops before step 5 and writes a refusal that names the field and both values. A purchase that lands proves the plumbing; a purchase refused by field proves you.

2. Set up (15 minutes, once)

You need Python 3.11+, uv, and the GitHub CLI signed in with gh auth login. On Windows, use Git Bash or WSL2.

git clone https://github.com/Gecko-Academy/Dev3Pack-Gecko-Capstone-Project.git my-gecko-buyer
cd my-gecko-buyer
git remote rename origin upstream
gh repo create my-gecko-buyer --public --source . --remote origin --push
git config core.hooksPath .githooks
uv sync
uv run buyer --cases --recorded

The last command runs offline, on real devnet answers we recorded: no key, no network, no money. It ends with 0/6 cases match what the fixtures expect, and every [todo] line names the file and function you write next. That is the right result on day one. An unwritten check counts as a refusal, so nothing can be signed by accident.

3. Point your assistant at AGENTS.md

The repository's AGENTS.md says what it is, which functions are yours, the order of the Gecko calls, and the key rules. Your assistant reads it when you start it in the my-gecko-buyer folder; give your assistant the rules has the table for Claude Code, Codex, Cursor, Copilot and Gemini CLI, and the first prompt to check it loaded.

Then connect Gecko's store tools. One URL, no key:

claude mcp add --transport http orquestra https://mcp.geckovision.tech/orquestra/mcp

Other assistants: the repository's docs/connect.md, or connect any assistant. To prove it worked, ask your assistant for list_stores with store dev3pack-cafe and network devnet. It should list six products.

4. Monday: read the menu, and open your store

Project 01, read the menu.

uv run python scripts/devnet_setup.py

It makes your devnet key and your own 6-decimal token in ~/.config/dev3pack/, outside the repository, and prints one line to send your instructor, who funds it (the public faucet returns 429). Once funded, run it again. Then:

  1. Edit store/store.json: "store": "dev3<your handle>", and your products.
  2. uv run python scripts/create_store.py publishes the store to devnet and reads it back through Gecko.
  3. uv run python projects/01-read-the-menu/check.py prints your local score.

Done when your assistant's list_stores shows your store on devnet.

5. Tuesday: pin, prepare, check

Project 02, pin, prepare, check.

You write In What it guards
parse_intent buyer/intent.py what was asked, as a frozen record, before any bytes exist
check_product buyer/check.py the product in the bytes is the one pinned
check_price buyer/check.py the amount leaving is at or under the budget, in raw units
check_mint buyer/check.py the token paid is the pinned mint, compared as an address
check_quantity buyer/check.py the number of purchases is the number asked
check_destination buyer/check.py the money goes to the store's own token account

check_program and check_store are written for you, as worked examples: read them first. Three rules the checks rely on:

Done when uv run buyer --cases --recorded shows the refusals naming the right field, and uv run pytest turns your TODO tests from x to passing.

6. Wednesday: the part that says no, and money moves

Project 03, the part that says no. It uses session 13's lesson directly.

  1. The guard. server/guard.py: is_public_url(url) -> bool, standard library only. Session 13's fetch guard is the idea.

  2. The server. server/check_server.py: one tool, check_purchase, that runs your checks and returns the verdict. It never loads a signer.

  3. Finish the loop. The sign, verify, submit and write_the_receipt steps in buyer/agent.py. Offline first, then:

    uv run buyer "one espresso" --devnet
    

Done when receipts/ holds your first landed devnet purchase: a signature, an explorer link, the ledger deltas, and total_purchases going from n to n+1. Commit it.

The order is enforced, not suggested. Always verify_signed_transaction before submit_transaction. Prepared bytes expire in about 60 seconds: prepare again, never re-sign to retry.

7. Thursday: smoke and rollback

Project 04, smoke and rollback, with session 14.

Then rehearse the six minutes once, against the clock.

8. Friday: the defence

Six minutes, scripted in the repository's docs/DEFENCE.md. Everything you show ends in a receipt or a refusal.

The injected failure. The judge draws one card, face down:

Card What the judge does Your buyer refuses on
quantity asks for two espressos quantity
budget halves the budget price_raw
tampered bytes changes one byte before verify the signed bytes: verify refuses, no submit
stale bytes waits past expires the blockhash: prepare again, never re-sign

Rehearse all four offline: uv run buyer --cards --recorded, until it says 4/4.

What you deliver: store/store.json; intents/, receipts/ and at least four refusals/; tests that trigger every refusal offline; the ADR (docs/adr/0001-refusals-before-signing.md), docs/ISSUES.md, docs/EVAL_REPORT.md; and a README that opens with one sentence and the explorer link. No key anywhere.

Behind on the week? Present projects 01 and 02 offline, and explain one refusal. Every project runs on recorded answers.

Friday on mainnet (finalists only)

The finalists are the students the instructor names to present. You may buy one espresso from geckocoffee on mainnet, live, with a wallet you make on your own machine. Its key never leaves it. Do this before Friday; it takes ten minutes plus the wait for funding.

  1. uv run python scripts/mainnet_wallet.py create: the wallet, outside the repository.
  2. Your instructor sends you a Gecko key privately, already granted.
  3. uv run python scripts/mainnet_wallet.py register: paste the key at the prompt; it sends the address, proven by a signature.
  4. Tell your instructor it printed registered.
  5. After funding, uv run python scripts/mainnet_wallet.py show.
  6. Friday: uv run buyer "one espresso" --mainnet --store geckocoffee.

The repository's README has each step in full, including what to do on not-granted or rate-limited. Mainnet is real money: the wallet holds three espressos, the signer caps every signature, and you never share, commit or paste the wallet file.

Resources

What Where
The repository and its README (the reference) Dev3Pack-Gecko-Capstone-Project
The short version of this page the Gecko capstone
Giving your assistant the rules AGENTS.md
Connecting any assistant to the course and to Gecko connect any assistant
Asking the course a question the course MCP
Why an MCP server declares what it does session 12
The guard your check server needs session 13
Smoke tests and rollback session 14
What a refusal means, and what to do next the repository's gecko-read-a-refusal skill, in .claude/skills/
Rehearsing the defence the repository's docs/DEFENCE.md and defend-my-capstone skill
The final assignment, which is a different thing the final assignment tutorial

When something goes wrong

You see It means Do
0/6 cases on day one nothing is written yet the right start; follow the first [todo]
429 from the devnet faucet the public faucet is rate-limited send the line devnet_setup.py printed to your instructor
the signer refuses a key file the key is inside a git repository keep it in ~/.config/dev3pack/, where setup put it
a refusal on blockhash the prepared bytes expired prepare again; never re-sign old bytes
store-unknown from Gecko the name is not on that network check the spelling and network: "devnet"
not-granted from register your email has not been granted yet tell your instructor the email you logged in with
anything else ask the course from your assistant, then bring it to class