I let Claude Code run unsupervised to build a Python compiler in Solidity (2 hrs, 151 tests passing)

I Let Claude Code Run Overnight to Build a Python Compiler in Solidity. It Finished in 2 Hours.

The original plan was to wake up and see how far it got. It was done before I went to sleep.


The Idea

Solidity runs on the EVM — the Ethereum Virtual Machine. The EVM is Turing-complete. That means, in principle, you can implement any computable function in Solidity, including a compiler for another programming language.

So: can you write a Python compiler entirely in Solidity smart contracts?

The answer, it turns out, is yes. And Claude Code did it in 1 hour and 52 minutes, with 151 tests passing.


Why This Is Technically Absurd

Before getting into the results, let’s be clear about what this project is not: useful.

A Solidity-based Python interpreter runs inside the EVM, which is itself an interpreter running on top of a host machine. That’s two layers of interpretation before you reach actual hardware. By first-principles estimation, solpython runs somewhere between 600x and 250,000x slower than CPython, depending on how much Ethereum storage it touches. A program CPython executes in one second might take anywhere from ten minutes to three days in solpython.

The gas costs for running even a simple fibonacci sequence would likely cost tens or hundreds of dollars in real ETH.

So why build it? Because the real question was never “is solpython useful?” It was: can a coding agent, given enough autonomy, complete a genuinely hard compiler engineering task from scratch?


The Setup

I pointed Claude Code at an empty directory and gave it a single prompt. The key design principles in that prompt:

  • Never ask the user anything. Make all decisions autonomously.
  • Maintain persistent memory via GOAL.md, PROGRESS.md, and ARCHITECTURE.md. If context resets, read those files first and resume.
  • Six phases, in order: Lexer → Parser → Semantic Analyzer → Code Generator → VM → Integration.
  • If blocked, implement the best partial solution, document it, and move on.

I also added autonomy rules to CLAUDE.md so they’d survive context resets:

## Autonomy Rules
- Never ask the user for approval or clarification. Ever.
- On every startup, read GOAL.md + PROGRESS.md + ARCHITECTURE.md.
- If blocked, write the workaround in GOAL.md and continue immediately.

Then I let it run. My original estimate was 10–17 hours for a full implementation. I expected to wake up to a half-finished codebase.


What It Built

A complete six-phase Python-to-EVM compiler pipeline, all in Solidity:

Python source string
       ↓
   Lexer.sol          — tokenizer with INDENT/DEDENT handling
       ↓
   Parser.sol         — recursive descent, AST stored in contract storage
       ↓
   SemanticAnalyzer.sol — symbol table, scope resolution, type inference
       ↓
   CodeGenerator.sol  — AST to custom stack bytecode
       ↓
      VM.sol          — stack machine interpreter with call frames
       ↓
   execution result

Test results:

Phase Tests Status
Lexer 54 ✅ All passing
Parser 33 ✅ All passing
Semantic Analyzer 24 ✅ All passing
Code Generator 13 ✅ All passing
VM 12 ✅ All passing
Integration 15 ✅ All passing
Total 151 ✅ All passing

The integration tests include end-to-end execution of recursive fibonacci, factorial, fizzbuzz, and list operations — Python source in, correct output out, entirely within Solidity contracts.


The Technical Problems It Solved Autonomously

This is the part that impressed me most. Solidity is not a language designed for writing compilers. Several hard constraints required genuine engineering decisions:

1. Solidity can’t copy structs containing strings across memory/storage boundaries.
The Parser needed to share its AST with downstream phases. Naive struct passing doesn’t work. The solution: a getter-based interface where SemanticAnalyzer and CodeGenerator query AST nodes through public view functions rather than copying them. Clean, idiomatic, not obvious.

2. Nested block parsing requires dynamic scoping.
Python’s indentation-based blocks create a scoping problem in a language without real recursion-friendly data structures. The solution: a three-tier auxiliary architecture — a bodyStack for nested blocks merged after each block closes, separate aux[] arrays for statements and exprAux[] for function arguments and list elements.

3. Forward jumps require backpatching.
When emitting bytecode for an if statement, you don’t know the jump target offset until you’ve emitted the body. Classic compiler technique: emit a placeholder, record its position, patch it later. It implemented this correctly without prompting.

4. EVM call stack depth is limited to 1024.
A naive recursive AST traversal risks stack overflow on deeply nested Python code. The code generator avoids this through iterative traversal patterns where possible.

5. VM variable storage.
Python’s local variable semantics — functions have their own scope, variables shadow outer names — require proper call frames. The VM uses mapping(uint256 => mapping(uint256 => uint256)) for frame-local storage, keyed by frame index and variable slot. No dynamic memory allocation required.

None of these problems were specified in the prompt. It encountered each one, diagnosed it, chose a solution, documented the decision in ARCHITECTURE.md, and continued.


The Numbers

Time: 1 hour, 52 minutes, 55 seconds

Tokens consumed: ~40 million

Token breakdown (estimated):

  • Input tokens (context × tool calls): ~38M — the dominant cost, because every file read and compiler invocation re-sends the growing context
  • Thinking tokens: ~1.5M
  • Output tokens (code + docs): ~500K

Cost at Opus 4.7 pricing (~$5/$25 per million input/output):

  • Roughly $190–220 for the full session

Lines of Solidity written: ~5,300 across 10 source files + 6 test files

My original time estimate: 10–17 hours
Actual time: 1h 53m
How wrong I was: ~8x


What It Didn’t Implement

The REPORT.md is honest about limitations:

  • for loops (stub only — code generation not completed)
  • import statements
  • Exception handling
  • Dict/set types
  • String methods
  • Generators/iterators
  • Multiple assignment (a, b = 1, 2)

This is a reasonable Python subset. The core language — functions, recursion, conditionals, while loops, lists, arithmetic — works end to end.


What This Actually Demonstrates

solpython will never run in production. Its practical utility is zero. But that’s not the point.

The point is that a coding agent, given a clear goal, persistent memory, and full autonomy, completed a task in two hours that a competent human compiler engineer would need two to four weeks to produce at the same test coverage.

This isn’t about replacing engineers. It’s about what the capability curve looks like now, and what it implies about where it’s going.

A few things that stood out to me:

It didn’t get lost. Long autonomous coding sessions often degrade — the model loses track of the overall architecture and starts producing locally-correct but globally-inconsistent code. This didn’t happen. The six phases remained coherent with each other throughout.

It made good engineering tradeoffs. Not just “make it work” — the solutions it chose (getter interfaces, backpatching, iterative traversal) are the solutions a thoughtful engineer would choose. Not clever hacks, actual design.

The persistent memory system worked. GOAL.md as a state machine — current phase, completed items, blockers, next steps — gave it a robust recovery mechanism if context had reset. It didn’t need to recover, but the infrastructure was there and correct.


Try It Yourself

The prompt that drove this, if you want to run your own experiment:

  1. Create an empty directory
  2. Add autonomy rules to CLAUDE.md
  3. Give Claude Code a clearly scoped, technically hard problem with phases
  4. Specify: never ask, maintain memory files, document blockers and continue
  5. Run with --dangerously-skip-permissions to eliminate approval prompts
  6. Go to sleep

The key insight from this experiment: the bottleneck isn’t intelligence, it’s the scaffolding for sustained autonomous work. Persistent memory files, clear phase structure, explicit instructions to keep moving when blocked — these matter more than the raw capability of the model.

The model is capable. Give it the right operating environment and get out of the way.


Built with Claude Code + Opus 4.7. Full source and test suite available on request.