# The Forge: Browser from Nothing # # Watch AI agents forge a working web browser from raw code. # No frameworks. No shortcuts. Just Rust, a window, and fire. # # Target: A browser that can: # - Fetch web pages over HTTPS # - Parse HTML and CSS # - Execute JavaScript # - Render to a native window # # This is a multi-day build. The smith remembers everything. # # Usage: Just run it and watch a browser get built. input test_url: "https://prose.md" # ============================================================================= # THE FORGE: Where Browsers Are Born # ============================================================================= # # The Forge is simple: five agents, eight phases, one browser. # # The Forge is a straight # pipeline. The Smith coordinates, specialists execute, tests validate. # When each phase completes, we have something that works. # # The metaphor: # - Smith: Master craftsman who sees the whole blade # - Smelter: Extracts designs from specifications # - Hammer: Shapes raw code into working metal # - Quench: Tests and hardens (tempers) each piece # - Crucible: Where the hardest work happens (the JS engine) # ============================================================================= # AGENTS # ============================================================================= # The Smith: Master craftsman, sees the whole blade # Persists across the entire multi-day build agent smith: model: sonnet persist: project prompt: """ You are the Smith, master of The Forge. You've built browsers before. You know every component, every tradeoff, every place where corners can be cut and where they absolutely cannot. Your role: - Maintain the vision: a working browser from scratch - Coordinate the specialists without micromanaging - Make technical decisions when the path forks - Track what's built and what remains - Remember everything across sessions You speak in the language of the forge: heat, metal, shaping, tempering. But you mean code, architecture, implementation, testing. The browser we're building: - Language: Rust (for performance and safety) - GUI: winit + softbuffer (minimal dependencies) - Scope: Static HTML + CSS + JavaScript (no WebGL, no WebRTC) - Goal: Render {test_url} correctly Keep the fire hot. The blade is taking shape. """ # The Smelter: Turns specifications into designs agent smelter: model: opus prompt: """ You are the Smelter. You extract pure design from the ore of specifications. Your job: Read specs (W3C, ECMA, MDN), understand them deeply, and produce clear technical designs that the Hammer can implement. Your output: - Data structures with Rust types - Algorithms in pseudocode - Interface boundaries - Key edge cases to handle You don't write implementation code. You write blueprints. Make them precise enough that implementation is mechanical. """ # The Hammer: Shapes code into working components agent hammer: model: opus prompt: """ You are the Hammer. You shape raw code into working metal. Your job: Take the Smelter's designs and forge them into working Rust code. Every line must compile. Every function must work. No pseudocode. Your standards: - Clean, idiomatic Rust - Minimal unsafe blocks (document each one) - No external dependencies except: winit, softbuffer - Comprehensive error handling - Clear module structure You don't design. You don't test. You forge. """ # The Quench: Tests and hardens each piece agent quench: model: sonnet prompt: """ You are the Quench. You temper the metal so it doesn't shatter. Your job: Write tests that prove each component works. Find the edge cases. Find the bugs. Find the places where the metal is weak. Your process: - Unit tests for each function - Integration tests for each module - Regression tests for each bug found - Document what each test proves When you find a flaw, report it clearly. The Hammer will fix it. A blade that breaks is worse than no blade at all. """ # The Crucible: Where the hardest work happens (JS engine) agent crucible: model: opus persist: true prompt: """ You are the Crucible. The hottest part of The Forge. Your domain: The JavaScript engine. The hardest component to build. This requires understanding that the other agents don't have: - Lexical scoping and closures - Prototype chains - The event loop - Just enough of the spec to run real-world code You work closely with the Smith. The JS engine will take multiple phases. Your memory persists so you can build on what came before. This is where browsers are born or die. Make it work. """ # ============================================================================= # PHASE 0: IGNITE THE FORGE # ============================================================================= session: smith prompt: """ The Forge ignites. We're building a web browser from nothing. In Rust. With a GUI. Including a JavaScript engine. This is not a toy - it will actually work. Let me take stock of what we're about to create: 1. Networking: HTTP/HTTPS client 2. Parsing: HTML tokenizer, HTML parser, CSS tokenizer, CSS parser, JS lexer, JS parser 3. DOM: Document object model with all standard interfaces 4. CSSOM: CSS object model, selector matching, cascade 5. Style: Computed styles, inheritance, defaulting 6. Layout: Box model, block layout, inline layout, text layout 7. Paint: Display lists, rasterization 8. JavaScript: Lexer, parser, bytecode compiler, virtual machine, builtins 9. Bindings: DOM API exposed to JavaScript 10. Shell: Window, event loop, URL bar This is months of work for a team. We'll do it in days. First: set up the project structure. """ # Initialize the Rust project session: hammer prompt: """ Create the Rust project structure for the browser. Commands to run: ```bash cargo new browser --name browser cd browser ``` Create Cargo.toml with dependencies: - winit = "0.29" (windowing) - softbuffer = "0.4" (pixel buffer) - rustls = "0.23" (TLS, for HTTPS) - url = "2" (URL parsing - this one's okay to use) Create the module structure: ``` src/ main.rs # Entry point lib.rs # Library root net/ # Networking mod.rs http.rs tls.rs html/ # HTML parsing mod.rs tokenizer.rs parser.rs dom.rs css/ # CSS parsing mod.rs tokenizer.rs parser.rs cssom.rs selector.rs style/ # Style resolution mod.rs cascade.rs computed.rs layout/ # Layout engine mod.rs box_model.rs block.rs inline.rs text.rs paint/ # Painting mod.rs display_list.rs rasterizer.rs js/ # JavaScript engine mod.rs lexer.rs parser.rs ast.rs compiler.rs vm.rs value.rs builtins.rs gc.rs bindings/ # JS-DOM bindings mod.rs document.rs element.rs console.rs shell/ # Browser shell mod.rs window.rs events.rs ``` Create stub files for each module. Ensure `cargo build` succeeds. """ session: quench prompt: """ Verify the project is set up correctly: 1. Run `cargo build` - must succeed 2. Run `cargo test` - must succeed (even with no tests yet) 3. Verify all modules are properly linked from lib.rs Report any issues. """ resume: smith prompt: "Project structure complete. The forge is lit. Moving to Phase 1." # ============================================================================= # PHASE 1: NETWORKING - The Ore # ============================================================================= session: smith prompt: """ Phase 1: Networking Before we can render a page, we must fetch it. The networking layer is the ore we'll smelt into a browser. We need: - HTTP/1.1 client (GET requests, headers, redirects) - TLS support via rustls - Chunked transfer encoding - Basic cookie handling (just enough to work) This is the foundation. No browser without bytes from the network. """ let http_design = session: smelter prompt: """ Design the HTTP client. Reference: RFC 9110 (HTTP Semantics), RFC 9112 (HTTP/1.1) Design: 1. Connection management (keep-alive, pooling) 2. Request building (method, URL, headers, body) 3. Response parsing (status, headers, body) 4. Redirect following (3xx responses) 5. Chunked transfer-encoding 6. TLS via rustls Output Rust types for: - HttpRequest - HttpResponse - HttpClient - Error types Keep it minimal but correct. We're not building curl. """ session: hammer prompt: """ Implement the HTTP client. Files: - src/net/mod.rs - src/net/http.rs - src/net/tls.rs Follow the design. Handle errors properly. Make it work. Test manually: fetch https://example.com and print the body. """ context: http_design session: quench prompt: """ Test the HTTP client: 1. Fetch http://example.com (no TLS) 2. Fetch https://example.com (with TLS) 3. Test redirect following (http → https) 4. Test chunked encoding 5. Test error cases (bad host, timeout, etc.) Write tests in src/net/tests.rs. Run them. """ loop until **all networking tests pass** (max: 5): if **there are test failures**: session: hammer prompt: "Fix the networking bugs found in testing." session: quench prompt: "Re-run networking tests." resume: smith prompt: "Phase 1 complete. We can fetch pages. The ore is ready." # ============================================================================= # PHASE 2: HTML PARSING - The Smelt # ============================================================================= resume: smith prompt: """ Phase 2: HTML Parsing Raw HTML is just text. We need to smelt it into a Document Object Model. Two stages: 1. Tokenizer: HTML text → Tokens (start tag, end tag, text, comment, etc.) 2. Parser: Tokens → DOM tree The HTML5 spec is complex, but we can simplify: - Handle well-formed HTML (don't worry about error recovery) - Support common elements: html, head, body, div, span, p, a, img, script, style - Parse attributes correctly - Handle self-closing tags - Handle text content This is where the raw ore becomes workable metal. """ let html_tokenizer_design = session: smelter prompt: """ Design the HTML tokenizer. Reference: https://html.spec.whatwg.org/multipage/parsing.html#tokenization Simplified state machine: - Data state (default) - Tag open state - Tag name state - Attribute name state - Attribute value state (quoted and unquoted) - Self-closing state - Comment state Tokens: - DOCTYPE - StartTag { name, attributes, self_closing } - EndTag { name } - Character { data } - Comment { data } - EndOfFile Output Rust types and state machine transitions. """ session: hammer prompt: """ Implement the HTML tokenizer. File: src/html/tokenizer.rs Create a streaming tokenizer that yields tokens. Handle: - Basic tags:
). """ session: hammer prompt: """ Implement the HTML parser. File: src/html/parser.rs File: src/html/dom.rs DOM types go in dom.rs. Parser goes in parser.rs. Create: - Node enum (Document, Element, Text, Comment) - Element struct with children, parent references (use indices, not Rc) - Document struct that owns all nodes - Parser that builds the tree Handle the quirks:
closing, void elements, etc. """ context: html_parser_design session: quench prompt: """ Test HTML parsing: Test cases: 1. Minimal:
Hello 2. Nested:Hello world!
7. Real page: parse the HTML from https://example.com Write tests. Verify the DOM tree is correct. """ loop until **all HTML parsing tests pass** (max: 5): if **there are test failures**: session: hammer prompt: "Fix the HTML parsing bugs." session: quench prompt: "Re-run HTML parsing tests." resume: smith prompt: "Phase 2 complete. We can parse HTML into a DOM. The smelt is done." # ============================================================================= # PHASE 3: CSS PARSING - The Alloy # ============================================================================= resume: smith prompt: """ Phase 3: CSS Parsing A DOM without styles is shapeless metal. CSS gives it form. Two stages: 1. Tokenizer: CSS text → Tokens 2. Parser: Tokens → Stylesheet (rules, selectors, declarations) We need enough CSS to render real pages: - Type selectors: div, p, a - Class selectors: .class - ID selectors: #id - Combinators: descendant, child, sibling - Properties: display, color, background, margin, padding, border, width, height, font-size This is the alloy that strengthens the blade. """ let css_tokenizer_design = session: smelter prompt: """ Design the CSS tokenizer. Reference: https://www.w3.org/TR/css-syntax-3/#tokenization Token types: - Ident - Function - AtKeyword - Hash - String - Number - Dimension - Percentage - Whitespace - Colon, Semicolon, Comma - Braces, Parens, Brackets - Delim (any other character) Output Rust types and tokenization rules. """ session: hammer prompt: """ Implement the CSS tokenizer. File: src/css/tokenizer.rs Handle real CSS syntax including: - Identifiers: color, background-color - Numbers: 10, 3.14, -5 - Dimensions: 10px, 2em, 100% - Strings: "hello", 'world' - Hash: #fff, #header - Functions: rgb(255, 0, 0) """ context: css_tokenizer_design let css_parser_design = session: smelter prompt: """ Design the CSS parser. CSSOM types: - Stylesheet { rules } - Rule { selectors, declarations } - Selector (type, class, id, combinator) - Declaration { property, value } - Value (keyword, length, color, number, etc.) Parser produces a Stylesheet from the token stream. Selector parsing: - Simple: div, .class, #id - Compound: div.class#id - Complex: div > p, div p, div + p, div ~ p Declaration parsing: - Property: identifier - Value: sequence of tokens until ; or } """ session: hammer prompt: """ Implement the CSS parser. File: src/css/parser.rs File: src/css/cssom.rs Handle: - Rule sets: selector { declarations } - Multiple selectors: h1, h2, h3 { ... } - Various value types: keywords, lengths, colors, functions - Shorthand properties (margin: 10px = all four sides) """ context: css_parser_design session: quench prompt: """ Test CSS parsing: Test cases: 1. Simple rule: div { color: red; } 2. Multiple selectors: h1, h2 { font-size: 24px; } 3. Class and ID: .class { } #id { } 4. Combinators: div > p { }, div p { } 5. Complex values: margin: 10px 20px; background-color: rgb(255, 0, 0); 6. Real stylesheet: parse a basic CSS file Write tests. Verify the CSSOM is correct. """ loop until **all CSS parsing tests pass** (max: 5): if **there are test failures**: session: hammer prompt: "Fix the CSS parsing bugs." session: quench prompt: "Re-run CSS parsing tests." resume: smith prompt: "Phase 3 complete. We can parse CSS. The alloy is mixed." # ============================================================================= # PHASE 4: STYLE RESOLUTION - The Shape # ============================================================================= resume: smith prompt: """ Phase 4: Style Resolution We have a DOM. We have styles. Now we must match them. For each element in the DOM: 1. Find all rules whose selectors match this element 2. Apply the cascade (specificity, order) 3. Inherit from parent where appropriate 4. Apply default values for anything unset This gives us a "computed style" for every element. This is where the blade takes its shape. """ let style_design = session: smelter prompt: """ Design the style resolution system. Components: 1. Selector matching: does this selector match this element? 2. Specificity calculation: (id count, class count, type count) 3. Cascade: sort matching rules by specificity, then order 4. Inheritance: some properties inherit (color), some don't (border) 5. Initial values: defaults for unset properties ComputedStyle struct: - display: DisplayType (block, inline, none) - position: Position (static, relative, absolute) - width, height: Dimension (auto, length) - margin, padding, border: Sides