Initial commit: Beyond the Prompt workshop presentation by Scott Scoble

- Reveal.js presentation on Skills and Subagents pattern
- Nix flake with Caddy-based HTTP server and process-compose orchestration
- ADRs documenting architectural decisions
- Skills for AI implementation guidance
- Full Scott Scoble author attribution in README
This commit is contained in:
Scott Scoble 2026-05-23 18:19:14 -07:00
commit d2da71e53a
33 changed files with 4865 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

View file

@ -0,0 +1,9 @@
{
"permissions": {
"allow": [
"Bash(grep:*)"
],
"deny": [],
"ask": []
}
}

192
CLAUDE.md Normal file
View file

@ -0,0 +1,192 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
A Nix flake-based project for the presentation "Beyond the Prompt: Lessons from Building with Claude Code". This project demonstrates using **Skills** for AI implementation guidance and **ADRs** for human documentation.
**Key Concept**: Skills provide scalable AI context (100s of patterns, minimal tokens), while ADRs document architectural rationale for humans.
## Project Structure
```
.
├── flake.nix # Nix flake with apps and devShell
├── CLAUDE.md # This file
├── skills/ # AI implementation skills (auto-loaded)
│ ├── nix-http-server/ # HTTP server creation skill
│ ├── revealjs-presentation/# Reveal.js presentation skill
│ └── adr-documentation/ # ADR creation skill
├── docs/
│ ├── adr/ # Architecture Decision Records (human docs)
│ │ ├── 001-presentation-technology.md
│ │ ├── 002-nix-flake-architecture.md
│ │ ├── 003-demo-implementation-strategy.md
│ │ └── README.md
│ └── demo/ # Conversation transcript and demo materials
│ └── README.md
└── presentation/
├── index.html # Reveal.js presentation
├── slides/
└── assets/
```
## Development Commands
### Nix Commands
```bash
# Enter development shell with all tools
nix develop
# Start presentation server (http://localhost:8000)
nix run .#present
# Start full demo (presentation + conversation viewer)
# - Presentation: http://localhost:8000
# - Conversation: http://localhost:8001
nix run .#demo
```
### Direct Development (Live Reload)
For rapid iteration without rebuilding:
```bash
nix develop
caddy file-server --root ./presentation --listen :8000
```
## Architecture
### Technology Stack
- **Presentation**: Reveal.js (CDN-hosted for simplicity)
- **HTTP Server**: Caddy (configured via Nix-generated Caddyfile)
- **Process Orchestration**: process-compose (YAML generated from Nix)
- **Multi-Platform**: Supports x86_64/aarch64 on Linux and macOS
### Available Skills (AI Guidance)
Claude Code auto-loads these skills for implementation guidance:
1. **nix-http-server**: Create HTTP servers using Caddy (NEVER Python). Enforces no-Python constraint from ADR 002.
2. **revealjs-presentation**: Build Reveal.js presentations optimized for large screens. Based on ADR 001 decision.
3. **adr-documentation**: Create ADRs for human documentation (not AI context).
**Context Efficiency**: 3 skills × ~100 tokens = 300 tokens for all metadata. Instructions only loaded when triggered.
### Architectural Decisions (Human Documentation)
ADRs in `docs/adr/` explain WHY (for humans, not AI):
1. **ADR 001**: Why Reveal.js (alternatives: Marp, Slidev, Beamer)
2. **ADR 002**: Why Caddy + process-compose (Python is verboten)
3. **ADR 003**: Why conversation-as-demo (meta-awareness approach)
### Flake Implementation
The flake uses:
- `forAllSystems` helper for multi-platform support
- `pkgs.writeText` to generate Caddyfile and process-compose configs
- `pkgs.writeScript` to create app wrappers
- No Python dependencies (Caddy replaces Python HTTP server)
## Configuration as Code
All configuration is generated from Nix expressions, not stored in the repo:
**Caddyfile generation**:
```nix
makeCaddyConfig = pkgs: port: root: pkgs.writeText "Caddyfile" ''
:${toString port} {
root * ${root}
file_server browse
encode gzip
}
'';
```
**process-compose YAML** (via JSON):
```nix
makeProcessComposeConfig = pkgs: processes:
pkgs.writeText "process-compose.yaml" (builtins.toJSON {
version = "0.5";
inherit processes;
});
```
## Development Workflow
### Making Changes
1. **Presentation updates**: Edit `presentation/index.html` or files in `presentation/`
2. **ADR updates**: Modify files in `docs/adr/`
3. **Flake updates**: Edit `flake.nix` based on ADR decisions
4. **Testing**: Run `nix run .#present` or `nix run .#demo`
### The Skills + ADRs Pattern
This project demonstrates the modern pattern:
```
Architectural Decision
↓
┌────┴────┐
▼ ▼
ADR Skill
(Human) (AI)
↓ ↓
Explains Implements
WHY HOW
```
**Workflow**:
1. Skills auto-load to guide implementation (no manual prompting needed)
2. ADRs available in `docs/adr/` when humans need to understand WHY
3. Update both when architecture evolves:
- ADR explains new decision rationale
- Skill encodes new implementation patterns
## Key Constraints
- **No Python**: Use Caddy or other nixpkgs servers
- **All deps from nixpkgs**: No external package managers
- **Configuration as code**: Generate configs, don't commit them
- **Multi-platform**: Support all major systems (Linux/macOS, x64/ARM)
## Demo Concept
The presentation demonstrates the Skills + ADRs pattern by using itself as the example:
- **ADRs** documented architectural decisions for humans
- **Skills** encoded those decisions as AI-executable patterns
- Constraints applied iteratively ("no Python" → enforced by skill)
- The conversation itself became the demo
- Implementation validates the approach
**Meta-insight**: This project evolved from ADR-driven to Skills+ADRs pattern during development, proving the context efficiency advantage.
## Commands Reference
```bash
# Development
nix develop # Enter dev shell
nix flake check # Validate flake (when checks added)
# Running apps
nix run .#present # Presentation only
nix run .#demo # Full demo environment
# Direct commands (from devShell)
caddy file-server --root ./presentation --listen :8000
process-compose up -f <config>
```
## Additional Notes
- Reveal.js loaded from CDN (can be vendored if offline needed)
- process-compose provides TUI for monitoring services
- Readiness probes ensure services are up before declaring ready
- Git history shows the evolution of the project

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Scott Scoble
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

100
README.md Normal file
View file

@ -0,0 +1,100 @@
# Beyond the Prompt: Lessons from Building with Claude Code
A presentation by **[Scott Scoble](https://scott.scoble.me)** about using Skills and Subagents to guide AI-assisted development, demonstrated through the FLUO project's FluoDSL sandboxing decision.
## Quick Start
```bash
# Clone the repository
git clone https://github.com/yourusername/beyond-the-prompt.git
cd beyond-the-prompt
# Start the presentation (requires Nix)
nix run .#present
```
Open http://localhost:8000 in your browser.
## Prerequisites
- [Nix](https://nixos.org/download.html) package manager with flakes enabled
## Commands
### Run Presentation Only
```bash
nix run .#present
```
Serves the presentation at http://localhost:8000
### Run Full Demo
```bash
nix run .#demo
```
Serves:
- Presentation at http://localhost:8000
- Conversation viewer at http://localhost:8001 (if available)
### Development Mode
```bash
# Enter development shell with all tools
nix develop
# Start presentation server with live reload
caddy file-server --root ./presentation --listen :8000
```
## Presenter Mode
Press `P` during the presentation to toggle presenter mode with speaker notes and timing.
Press `C` to clone the slideshow for dual-screen presentation.
## Key Keyboard Shortcuts
- `→` / `Space` - Next slide
- `←` - Previous slide
- `P` - Toggle presenter mode
- `C` - Clone slideshow
- `F` - Toggle fullscreen
- `?` - Show help
## Project Structure
```
.
├── flake.nix # Nix flake with apps and devShell
├── README.md # This file
├── CLAUDE.md # Instructions for Claude Code
├── docs/
│ ├── adr/ # Architecture Decision Records
│ └── demo/ # Demo materials
└── presentation/
├── index.html # Reveal.js presentation
├── slides.md # Presentation content
├── assets/ # Images, CSS, themes
└── vendor/ # Vendored dependencies
```
## Content
This presentation covers:
1. **Context Window Economics** - Progressive disclosure and token efficiency
2. **Skills + Subagents Pattern** - HOW to implement vs SHOULD we build
3. **Preventing Waste** - Evaluation before execution
## Learn More
- FLUO Project: https://github.com/fluohq/fluo
- See `.skills/` and `.subagents/` directories in FLUO for implementation examples
- Read ADRs in `docs/adr/` for architectural context
## License
MIT License - see [LICENSE](LICENSE) file for details

View file

@ -0,0 +1,89 @@
# ADR 001: Presentation Technology Choice
## Status
Proposed
## Context
We need to create a presentation for "Beyond the Prompt: Lessons from Building with Claude Code" that:
- Can be served via simple HTTP server
- Works well with Nix flake distribution
- Supports code syntax highlighting
- Allows for presenter notes
- Is version-controllable (text-based)
- Can be easily edited and previewed
## Decision
Use **Reveal.js** for the presentation framework.
## Rationale
### Reveal.js Advantages
- **Static HTML/JS/CSS**: Can be served with any simple HTTP server
- **Rich features**: Code highlighting, presenter notes, speaker view, PDF export
- **Nix-friendly**: Available via nixpkgs, no complex build process
- **Offline-capable**: All assets can be bundled
- **Markdown support**: Can write slides in Markdown within HTML
- **Wide adoption**: Well-documented, stable, extensive plugin ecosystem
### Alternatives Considered
**Marp**
- Pros: Pure Markdown, simpler syntax
- Cons: Requires CLI tool, more complex Nix integration, fewer interactive features
- Verdict: Too limiting for technical demos
**Slidev**
- Pros: Vue-based, modern developer experience
- Cons: Requires Node.js build process, heavier Nix integration
- Verdict: Unnecessary complexity for this use case
**Beamer/LaTeX**
- Pros: Academic standard, precise control
- Cons: PDF-only, no interactive demos, steep learning curve
- Verdict: Not suitable for live coding demonstrations
## Implementation Details
### Directory Structure
```
presentation/
├── index.html # Main presentation file
├── css/
│ └── theme/ # Custom themes if needed
├── js/
│ └── reveal.js # Vendored or symlinked
└── assets/
├── images/
└── code-samples/
```
### Serving
- Development: `nix run .#present` → lightweight HTTP server from nixpkgs (e.g., darkhttpd, caddy, or miniserve)
- Production: Static hosting (GitHub Pages, Netlify, etc.)
### Reveal.js Integration in Nix
Use nixpkgs to fetch reveal.js dependencies:
- Option 1: `fetchFromGitHub` to get reveal.js source
- Option 2: Use `buildNpmPackage` if npm-based tooling needed
- Option 3: Direct vendoring with `fetchurl` for specific release
Recommended: **fetchFromGitHub** for reproducibility and ease of updates.
## Consequences
### Positive
- Simple development workflow
- No build step required for basic presentations
- Easy to version control
- Works offline
- Familiar to many developers
### Negative
- Manual Reveal.js updates (if vendored)
- Larger repo size if vendoring full Reveal.js
- Less separation between content and presentation (vs. pure Markdown)
### Mitigation
- Keep Reveal.js minimal (only required files)
- Use Markdown mode for slide content where possible
- Document update process for Reveal.js version bumps

View file

@ -0,0 +1,245 @@
# ADR 002: Nix Flake Architecture
## Status
Proposed
## Context
The project needs a Nix flake that:
- Provides reproducible development environment
- Defines two runnable apps: `present` and `demo`
- Supports multiple platforms (Linux and macOS, both x64 and ARM)
- Minimizes complexity while providing good developer experience
- Follows Nix best practices
## Decision
Implement a multi-platform flake with `forAllSystems` helper, separate apps for presentation and demo, and a comprehensive devShell.
## Architecture
### System Support
```nix
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
```
### Core Outputs
1. **apps.present**
- Type: `app`
- Function: Serve presentation on http://localhost:8000
- Implementation: process-compose orchestrating Caddy server
- Configuration: Nix-generated Caddyfile and process-compose.yaml
2. **apps.demo**
- Type: `app`
- Function: Execute demonstration script
- Implementation: process-compose orchestrating demo processes
- Configuration: Nix-generated process-compose.yaml for demo services
3. **devShells.default**
- Purpose: Development environment with all necessary tools
- Contents: bash, caddy, process-compose, and optional tools (asciinema, etc.)
- Shell hook: Display helpful usage instructions
## Rationale
### Multi-Platform with forAllSystems
**Why**: Developers use various platforms; presentation should work everywhere
**How**: Use `nixpkgs.lib.genAttrs` to generate outputs for all systems
**Alternative**: Single-platform support would exclude contributors
### Separate Apps vs Unified Interface
**Decision**: Two separate apps (`present` and `demo`)
**Why**:
- Clear separation of concerns
- Can run independently
- Better UX (`nix run .#present` is more explicit than `nix run . -- present`)
**Alternative considered**: Single app with subcommands
- Would require argument parsing
- More complex implementation
- Less idiomatic for Nix
### writeScript vs Packages
**Decision**: Use `pkgs.writeScript` for app wrappers
**Why**:
- Simple bash scripts don't need full package machinery
- Reduces boilerplate
- Direct access to flake's `self` reference
- Easier to maintain
**Alternative**: Proper derivations with `stdenv.mkDerivation`
- Overkill for simple wrappers
- More complex to reference source files
### HTTP Server and Process Management
**Decision**: Use **Caddy** for HTTP serving, orchestrated by **process-compose**
**Architecture**:
- **Caddy**: Modern HTTP server with automatic HTTPS, JSON API, config reloading
- **process-compose**: Process orchestrator (alternative to docker-compose for processes)
- **Configuration**: Generated via Nix expressions, no manual config files
**Why Caddy**:
- Configuration as code via Nix
- JSON/Caddyfile generation from Nix expressions
- Powerful features (reverse proxy, file server, API)
- Good developer experience
- Available in nixpkgs
**Why process-compose**:
- Orchestrates multiple services (presentation server, potential demo services)
- YAML config generated from Nix
- Terminal UI for monitoring processes
- Graceful shutdown and dependency management
- Better than ad-hoc bash scripts for multi-process apps
**Configuration Strategy**:
```nix
# Generate Caddyfile
caddyConfig = pkgs.writeText "Caddyfile" ''
:8000 {
root * ${self}/presentation
file_server
encode gzip
}
'';
# Generate process-compose config
processComposeConfig = pkgs.writeText "process-compose.yaml" (builtins.toJSON {
processes = {
presentation = {
command = "${pkgs.caddy}/bin/caddy run --config ${caddyConfig}";
readiness_probe = {
http_get = {
host = "localhost";
port = 8000;
};
};
};
};
});
```
### DevShell Philosophy
**Decision**: Include common tools, comment optional ones
**Why**:
- Balance between "batteries included" and minimalism
- Comments serve as documentation
- Easy to uncomment tools as needed
- Shell hook provides guidance
## Implementation Details
### Flake Structure
```nix
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
outputs = { self, nixpkgs }:
let
supportedSystems = [ ... ];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems
(system: f system (import nixpkgs { inherit system; }));
in {
apps = forAllSystems (system: pkgs: { ... });
devShells = forAllSystems (system: pkgs: { ... });
};
}
```
### App Implementation Pattern
```nix
present = {
type = "app";
program = "${pkgs.writeScript "present" ''
#!/usr/bin/env bash
exec ${pkgs.process-compose}/bin/process-compose \
up -f ${processComposeConfig}
''}";
};
```
### Configuration File Generation
**Caddy Configuration** (Caddyfile):
```nix
caddyConfig = pkgs.writeText "Caddyfile" ''
:8000 {
root * ${self}/presentation
file_server browse
encode gzip
log {
output stdout
format console
}
}
'';
```
**process-compose Configuration** (YAML via JSON):
```nix
# YAML generation using builtins.toJSON for structured config
processComposeConfig = pkgs.writeText "process-compose.yaml" (
builtins.toJSON {
version = "0.5";
processes = {
caddy = {
command = "${pkgs.caddy}/bin/caddy run --config ${caddyConfig}";
readiness_probe = {
http_get = {
host = "localhost";
port = 8000;
};
};
};
};
}
);
```
### Source File References
- Presentation: `${self}/presentation`
- Demo files: `${self}/demo/`
- Configs are generated, not stored in repo
## Consequences
### Positive
- Reproducible across all major platforms
- Configuration as code (no manual config files)
- Process orchestration with monitoring UI
- Clean separation: presentation vs demo
- Graceful shutdown and process management
- Readiness probes ensure services are up
- All dependencies from nixpkgs
### Negative
- process-compose adds complexity vs simple HTTP server
- Files copied to Nix store (not live-reloaded during development)
- Need to re-run `nix run` after file changes
- YAML generation via JSON (no native YAML in Nix)
### Mitigation
- Complexity justified by better orchestration and monitoring
- For rapid iteration, use devShell with direct commands:
```bash
nix develop
# Then run Caddy directly for live development:
caddy run --config <(echo ':8000 { root * ./presentation; file_server }')
```
- process-compose TUI provides visibility into running services
- JSON→YAML conversion is transparent and well-tested
## Future Considerations
- Add `checks` output for presentation validation (broken links, etc.)
- Add `packages` output for static site generation
- Consider `nix flake init` template for similar presentations
- Add formatter (e.g., alejandra) to devShell
- Explore Caddy admin API for dynamic config updates
- Add hot-reload capability using Caddy's config API
- Consider additional process-compose processes for demo infrastructure

View file

@ -0,0 +1,235 @@
# ADR 003: Demo Implementation Strategy
## Status
Accepted
## Context
The presentation "Beyond the Prompt: Lessons from Building with Claude Code" needs to demonstrate:
- How to use ADRs to guide AI-assisted development
- Effective prompt engineering and task decomposition
- Iterative refinement with architectural constraints
- Real-world workflow patterns with Claude Code
The demo must be:
- Authentic and realistic
- Reproducible for attendees
- Illustrative of actual development patterns
- Version-controlled and sharable
## Decision
**The demo IS the development conversation itself** - specifically, the conversation that builds this presentation system using ADRs to guide Claude Code.
The demo consists of:
1. The ADRs that define the architecture (stored in `docs/adr/`)
2. The conversation transcript showing iterative development
3. The resulting implementation (flake, presentation, etc.)
## Rationale
### Why Conversation-as-Demo
**Authenticity**: Shows real Claude Code usage, not simulation
- Actual tool interactions
- Real decision-making process
- Genuine iterative refinement
- True constraint handling
**Educational Value**: Demonstrates the meta-pattern
- ADRs provide clear boundaries and context
- Constraints drive better design (e.g., "no Python", "use nixpkgs")
- Iterative improvement based on feedback
- Architecture emerges from conversation
**Reproducibility**: Attendees can recreate the pattern
- ADRs are templates for their own projects
- Conversation style is learnable
- Git history shows evolution
- Implementation validates the approach
### Alternative Approaches Considered
**1. Scripted Demo with Simulated Output**
- Pros: Predictable, rehearsable, no live risk
- Cons: Inauthentic, doesn't show real tool, feels staged
- Verdict: Misses the point of "beyond the prompt"
**2. Live Coding Session**
- Pros: Shows real tool, spontaneous
- Cons: Unpredictable, time pressure, can't capture nuance
- Verdict: Too risky for complex architecture decisions
**3. Pre-recorded Video**
- Pros: Perfect execution, editing possible
- Cons: Not interactive, can't adapt to audience questions
- Verdict: Loses conversational flow and learning opportunities
## Implementation Details
### Demo Artifacts
**1. Architecture Decision Records** (`docs/adr/`)
- `001-presentation-technology.md` - Reveal.js choice
- `002-nix-flake-architecture.md` - process-compose + Caddy
- `003-demo-implementation-strategy.md` - This document (meta!)
- `README.md` - ADR index and usage guide
**2. Conversation Transcript** (`docs/demo/`)
Store the actual Claude Code conversation showing:
- Initial requirements gathering
- ADR creation and refinement
- Constraint application ("no Python")
- Architecture evolution (simple → process-compose)
- Decision rationale and tradeoffs
**3. Implementation Artifacts**
- `flake.nix` - The actual working implementation
- `presentation/` - Reveal.js presentation
- Git commits showing progression
### Demo Execution Flow
**Stage 1: Setup** (2 minutes)
- Show empty repo with just README
- Explain the goal: build a presentation system
- Introduce ADRs as the guiding pattern
**Stage 2: ADR Creation** (3 minutes)
- Walk through creating ADR 001 (presentation tech)
- Show how it evaluates alternatives
- Demonstrate decision rationale
**Stage 3: Constraint Refinement** (3 minutes)
- Show conversation applying constraints
- Example: "No Python" → rearchitecture to Caddy
- Demonstrate ADR updates reflecting new decisions
**Stage 4: Implementation Validation** (2 minutes)
- Run `nix run .#present` to prove it works
- Show generated configs (Caddyfile, process-compose.yaml)
- Demonstrate configuration-as-code
**Stage 5: Meta-Reflection** (2 minutes)
- Highlight the pattern: ADRs → Conversation → Implementation
- Show how this approach is reusable
- Provide takeaways for attendees
### Presentation Integration
Embed demo artifacts in the presentation:
```markdown
# Slide: "The Power of ADRs"
- Show ADR 001 side-by-side with implementation
- Highlight how decisions map to code
# Slide: "Iterative Refinement"
- Show conversation excerpt about Python → Caddy
- Display the updated ADR section
- Show the resulting Nix code
# Slide: "Meta Demo"
- Reveal that THIS presentation was built this way
- Show the actual conversation
- Provide GitHub link for full exploration
```
### Nix Integration
The demo app serves the conversation transcript:
```nix
demo = {
type = "app";
program = "${pkgs.writeScript "demo" ''
#!/usr/bin/env bash
# Generate demo config for process-compose
config="${pkgs.writeText "demo-compose.yaml" (builtins.toJSON {
processes = {
conversation-viewer = {
command = "${pkgs.caddy}/bin/caddy file-server --root ${self}/docs/demo --listen :8001";
};
presentation = {
command = "${pkgs.caddy}/bin/caddy file-server --root ${self}/presentation --listen :8000";
};
};
})}"
exec ${pkgs.process-compose}/bin/process-compose up -f "$config"
''}";
};
```
This runs:
- Presentation on `:8000`
- Conversation transcript viewer on `:8001`
## Technical Considerations
### Conversation Capture
- Export Claude Code conversation to markdown
- Format with syntax highlighting
- Preserve timestamps and flow
- Annotate with insights
### Presentation Structure
```
presentation/
├── index.html # Main reveal.js presentation
├── slides/
│ ├── 01-introduction.md
│ ├── 02-the-adr-pattern.md
│ ├── 03-demo-reveal.md # The meta moment
│ └── 04-takeaways.md
└── assets/
├── conversation.md # Embedded transcript excerpts
├── adr-examples/ # ADR screenshots
└── implementation/ # Code snippets
```
### Git History as Artifact
Commit strategy:
```
feat: initial ADRs for presentation architecture
feat: update ADR 002 with process-compose approach
feat: rewrite ADR 003 as conversation-based demo
feat: implement flake based on ADR decisions
docs: add conversation transcript to demo/
```
Git history itself becomes part of the demo narrative.
## Consequences
### Positive
- **Authentic**: Real Claude Code usage, not simulation
- **Educational**: Shows thinking process, not just results
- **Reusable**: Pattern applicable to any project
- **Transparent**: All decisions documented and traceable
- **Self-documenting**: The demo explains itself
- **Meta-awareness**: Presentation about AI development, built with AI
### Negative
- **Complexity**: More sophisticated than simple script
- **Preparation**: Requires curating conversation for clarity
- **Length**: Full conversation may be too detailed for presentation
- **Assumption**: Assumes audience familiarity with ADRs
### Mitigation
- Curate conversation to key decision points
- Provide full transcript as supplementary material
- Include ADR primer in presentation intro
- Offer simplified "getting started" guide for newcomers
## Future Enhancements
- Interactive conversation explorer (search, filter by topic)
- Side-by-side view: ADR ↔ Conversation ↔ Implementation
- Jupyter notebook walking through the process step-by-step
- Template repository: "instant ADR-driven development"
- Video walkthrough with narration over the conversation
- Browser extension to capture Claude Code conversations automatically
## Key Insight
**This ADR is itself part of the demo** - it documents the decision to use the conversation as the demo, demonstrating the recursive, self-referential nature of effective AI-assisted development.
The presentation is its own case study.

80
docs/adr/README.md Normal file
View file

@ -0,0 +1,80 @@
# Architecture Decision Records
This directory contains Architecture Decision Records (ADRs) for the "Beyond the Prompt" presentation project.
## Purpose: Human Documentation
**ADRs are for humans, not AI.** They explain WHY architectural decisions were made, document alternatives considered, and preserve historical context for team members.
**For AI implementation guidance**, see the `/skills` directory. Skills encode HOW to implement the decisions documented in ADRs.
## Index
1. [ADR 001: Presentation Technology Choice](./001-presentation-technology.md) → *Skill: `revealjs-presentation`*
- Decision to use Reveal.js for the presentation
- Rationale, alternatives, and implementation approach
2. [ADR 002: Nix Flake Architecture](./002-nix-flake-architecture.md) → *Skill: `nix-http-server`*
- Multi-platform flake design
- App structure and devShell configuration
- **Key constraint**: No Python dependencies
3. [ADR 003: Demo Implementation Strategy](./003-demo-implementation-strategy.md) → *Skill: `adr-documentation`*
- Conversation-as-demo approach
- Meta-awareness and documentation strategy
## ADR Format
Each ADR follows this structure:
- **Status**: Proposed, Accepted, Deprecated, Superseded
- **Context**: The problem or situation
- **Decision**: What was decided
- **Rationale**: Why this decision was made (including alternatives)
- **Consequences**: Positive, negative, and mitigations
## When to Write an ADR
Create an ADR when making architectural decisions that:
- Affect multiple parts of the system
- Have long-term implications
- Involve trade-offs between alternatives
- Need to be communicated to future contributors
**After writing an ADR**, consider creating a corresponding **Skill** if:
- The decision involves repetitive implementation patterns
- AI should automatically enforce the decision's constraints
- The pattern can be automated with templates/scripts
- You want perfect consistency in implementation
## The ADR + Skill Pattern
```
Make Decision
↓
┌────┴────┐
▼ ▼
ADR Skill
↓ ↓
WHY HOW
Human AI
```
**Example**: ADR 002 documents WHY we chose Caddy (no Python constraint). The `nix-http-server` skill enforces this by NEVER suggesting Python servers.
## Context Efficiency
**Old approach**: Load ADRs into AI context
- 3 ADRs × 1,500 tokens = 4,500 tokens before writing code
- Doesn't scale beyond ~10-20 ADRs
**New approach**: Use Skills for AI, ADRs for humans
- 3 skills × 100 tokens metadata = 300 tokens
- Scales to 100s of patterns
- ADRs remain available for human readers
## Updating ADRs
ADRs are immutable once accepted. To change a decision:
1. Create a new ADR that supersedes the old one
2. Update the old ADR's status to "Superseded by ADR XXX"
3. Update or create corresponding skill to reflect new implementation pattern

64
docs/demo/README.md Normal file
View file

@ -0,0 +1,64 @@
# Demo: The Conversation
This directory contains the actual conversation that built this presentation system, demonstrating the ADR-driven development approach with Claude Code.
## What's Here
- **conversation-transcript.md** - The full development conversation
- **key-moments.md** - Highlighted decision points from the conversation
- **lessons-learned.md** - Insights and patterns discovered
## Viewing the Demo
When you run `nix run .#demo`, this content is served on http://localhost:8001 alongside the presentation on http://localhost:8000.
## The Meta Pattern
This demo demonstrates:
1. **ADRs as guardrails** - How Architecture Decision Records guide AI development
2. **Iterative refinement** - Constraint application (e.g., "no Python" → Caddy)
3. **Conversation as artifact** - The dialogue itself becomes valuable documentation
4. **Meta-awareness** - Building a presentation about AI development, with AI
## Key Decision Points
### Initial Setup
- Created ADRs to define architecture
- Established technology choices (Reveal.js, Nix)
### Constraint Application
- "Python is verboten" → Evaluated alternatives
- Chose Caddy over darkhttpd/miniserve
- Added process-compose for orchestration
### Meta Realization
- "The demo IS this conversation"
- Shifted from scripted demo to conversation-as-demo
- Updated ADR 003 to reflect this approach
### Implementation
- Built flake.nix based on ADR 002
- Generated configs from Nix expressions
- Multi-platform support with forAllSystems
## Lessons Learned
1. **ADRs provide crucial context** - They help AI understand not just what to build, but why
2. **Constraints drive better design** - "No Python" led to a more robust architecture
3. **Iterative refinement works** - First solutions improved through dialogue
4. **Meta-awareness is powerful** - Using the tool to understand the tool
## Try It Yourself
1. Read through the ADRs in `docs/adr/`
2. Study the conversation transcript
3. Examine the resulting `flake.nix`
4. Apply the pattern to your own projects
The pattern is simple:
```
ADRs → Conversation → Implementation → Refinement → Better ADRs
```
This creates a virtuous cycle of improvement.

View file

150
docs/presentation-timing.md Normal file
View file

@ -0,0 +1,150 @@
# Presentation Timing Guide
**Target Duration**: 110 minutes total
**Format**: Cumulative timestamps for each slide
---
## Introduction & Setup (15 min total)
| Slide # | Title | Time | Cumulative | Notes |
|---------|-------|------|------------|-------|
| 1 | Beyond the Prompt (Title) | 2 min | 0:02 | Welcome, introduce topic |
| 2 | Who Am I? | 2 min | 0:04 | Brief intro, keep it tight |
| 3 | Let's Dive In (Image) | 0:30 | 0:04:30 | Visual transition only |
| 4 | The Request | 2 min | 0:06:30 | Set up the problem, audience question |
| 5 | So I Asked Claude Code | 1:30 | 0:08 | Bridge to context windows |
| 6 | Part 1: The Problem | 0:30 | 0:08:30 | Section title card |
| 7 | The Context Window Problem | 3 min | 0:11:30 | Audience question about ADRs, relatable |
| 8 | Progressive Disclosure | 4 min | 0:15:30 | Core concept, needs time to land |
---
## Part 1: Context Window Economics (20 min total from start)
| Slide # | Title | Time | Cumulative | Notes |
|---------|-------|------|------------|-------|
| 9 | FLUO's Token Budget | 3 min | 0:18:30 | Show the math, 95% reduction |
| 10 | Quick Check | 2 min | 0:20:30 | Audience calculates their ADRs |
---
## Part 2: The Pattern - Dream Team Story (40 min total from start)
| Slide # | Title | Time | Cumulative | Notes |
|---------|-------|------|------------|-------|
| 11 | Back to Sandboxing | 1 min | 0:21:30 | Remind the problem |
| 12 | Part 2: Building a Dream Team | 1 min | 0:22:30 | Section title, metaphor intro |
| 13 | The Implementer Speaks | 3 min | 0:25:30 | First agent, audience interaction |
| 14 | Round 2: Architecture Guardian | 4 min | 0:29:30 | **KEY SLIDE** - Java 17 deprecation reveal |
| 15 | Round 3: Security Expert | 3 min | 0:32:30 | Security rating, audience question |
| 16 | Round 4: QA Expert | 2 min | 0:34:30 | Testing requirements |
| 17 | Round 5: Product Manager | 4 min | 0:38:30 | **KEY SLIDE** - ROI calculation, decision |
| 18 | The Punchline | 5 min | 0:43:30 | **KEY SLIDE** - 3 days actual, 12 weeks saved |
| 19 | Next Steps | 2 min | 0:45:30 | Transition to Part 3 |
---
## Part 3: How to Build This (50 min total from start)
| Slide # | Title | Time | Cumulative | Notes |
|---------|-------|------|------------|-------|
| 20 | Part 3: How to Build This | 1 min | 0:46:30 | Section title |
| 21 | Your Dream Team | 5 min | 0:51:30 | **KEY SLIDE** - 4 agents, start with 2 |
| 22 | Subagent Anatomy | 8 min | 0:59:30 | **MAJOR SLIDE** - Walk through YAML, Q&A |
| 23 | Skill Anatomy | 7 min | 1:06:30 | **MAJOR SLIDE** - Example code, explain parts |
| 24 | The Evaluation Loop | 5 min | 1:11:30 | Workflow, timing breakdown |
| 25 | Real Numbers from FLUO | 4 min | 1:15:30 | ROI, concrete results |
---
## Closing & Comparison (30 min remaining)
| Slide # | Title | Time | Cumulative | Notes |
|---------|-------|------|------------|-------|
| 26 | FLUO's Results | 2 min | 1:17:30 | Summary stats |
| 27 | The Pattern | 2 min | 1:19:30 | "Evaluate first" principle |
| 28 | Skills vs Subagents | 5 min | 1:24:30 | **KEY SLIDE** - Clarify difference, table |
| 29 | The Three Topics | 3 min | 1:27:30 | Recap the structure |
| 30 | The Real Story | 4 min | 1:31:30 | Circle back to PRD-005 |
| 31 | Try It Yourself | 3 min | 1:34:30 | FLUO repo, getting started |
| 32 | Thank You / Questions | 15:30 | 1:50 | **Q&A** - buffer for audience questions |
---
## Key Time Allocations
**Longest slides (need most time):**
1. **Subagent Anatomy** (8 min) - Walking through code, explaining structure
2. **Skill Anatomy** (7 min) - Concrete example with explanation
3. **Your Dream Team** (5 min) - Critical decision point for audience
4. **The Punchline** (5 min) - Payoff moment, needs to land
5. **Skills vs Subagents** (5 min) - Clarifying core concepts
6. **The Evaluation Loop** (5 min) - Practical workflow
**Story beats that need room:**
- Architecture Guardian catching Java 17 issue (4 min)
- Product Manager ROI calculation (4 min)
- Real Numbers from FLUO (4 min)
**Quick transitions:**
- Section title cards (0:30-1 min each)
- Visual slides (0:30)
- Bridge slides (1-2 min)
---
## Pacing Strategy
**First 20 minutes**: Build the problem (context windows)
- Hook them with relatable pain
- Show the constraint clearly
**Minutes 20-45**: Tell the story (dream team saves the day)
- Drama: almost shipped bad code
- Resolution: team caught it
- Payoff: 3 days vs 12 weeks
**Minutes 45-75**: Teach the specifics (how to build it)
- Slow down here, give them copy-able templates
- This is what they'll use on Monday
**Minutes 75-95**: Wrap up and context (comparison, recap)
- Tie it together
- Answer "where do I start?"
**Minutes 95-110**: Q&A
- Reserve 15 minutes minimum
- Likely to run over if audience is engaged
---
## Emergency Adjustments
**If running long:**
- Skip slide 26 (FLUO's Results) - covered in slide 25
- Shorten Q&A to 10 minutes
- Reduce Subagent/Skill Anatomy by 2 min each
**If running short:**
- Extend Q&A
- Add war stories during Part 2
- Deep dive on Skills vs Subagents table
**Critical slides (never skip):**
- #8: Progressive Disclosure
- #14: Architecture Guardian (Java 17)
- #17: Product Manager (ROI)
- #18: The Punchline
- #22-23: Anatomy slides
- #28: Skills vs Subagents
---
## Checkpoints
- **30 minutes**: Should be at slide 14 (Architecture Guardian)
- **60 minutes**: Should be at slide 22 (Subagent Anatomy)
- **90 minutes**: Should be at slide 30 (The Real Story)
- **95 minutes**: Start Q&A
If you're behind at any checkpoint, tighten up the next section. If ahead, add stories or extend Q&A.

27
flake.lock generated Normal file
View file

@ -0,0 +1,27 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1760524057,
"narHash": "sha256-EVAqOteLBFmd7pKkb0+FIUyzTF61VKi7YmvP1tw4nEw=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "544961dfcce86422ba200ed9a0b00dd4b1486ec5",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

223
flake.nix Normal file
View file

@ -0,0 +1,223 @@
{
description = "Beyond the Prompt: Lessons from Building with Claude Code";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
outputs = { self, nixpkgs }:
let
# Systems to support
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
# Helper function to generate outputs for all systems
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system (import nixpkgs { inherit system; }));
# Generate Caddyfile for presentation
makeCaddyConfig = pkgs: port: root: pkgs.writeText "Caddyfile" ''
:${toString port} {
root * ${root}
file_server browse
encode gzip
log {
output stdout
format console
}
}
'';
# Generate process-compose config
makeProcessComposeConfig = pkgs: processes: pkgs.writeText "process-compose.yaml" (
builtins.toJSON {
version = "0.5";
inherit processes;
}
);
in
{
# Apps for each system
apps = forAllSystems (system: pkgs: {
# Presentation server
present = {
type = "app";
program = "${pkgs.writeScript "present" ''
#!/usr/bin/env bash
set -euo pipefail
# Use current working directory for development
PRESENTATION_ROOT="$PWD/presentation"
if [ ! -d "$PRESENTATION_ROOT" ]; then
echo "Error: presentation/ directory not found in current directory"
echo "Please run this command from the project root"
exit 1
fi
# Generate Caddyfile at runtime
CADDY_CONFIG=$(mktemp)
trap "rm -f $CADDY_CONFIG" EXIT
cat > "$CADDY_CONFIG" <<EOF
:8000 {
root * $PRESENTATION_ROOT
file_server browse
encode gzip
log {
output stdout
format console
}
}
EOF
# Generate process-compose config at runtime
COMPOSE_CONFIG=$(mktemp)
trap "rm -f $COMPOSE_CONFIG" EXIT
cat > "$COMPOSE_CONFIG" <<EOF
{
"version": "0.5",
"processes": {
"presentation": {
"command": "${pkgs.caddy}/bin/caddy run --config $CADDY_CONFIG --adapter caddyfile",
"readiness_probe": {
"http_get": {
"host": "localhost",
"port": 8000
}
}
}
}
}
EOF
echo "Starting presentation server on http://localhost:8000"
exec ${pkgs.process-compose}/bin/process-compose up -f "$COMPOSE_CONFIG" --tui=false
''}";
};
# Demo: serves both presentation and conversation transcript
demo = {
type = "app";
program = "${pkgs.writeScript "demo" ''
#!/usr/bin/env bash
set -euo pipefail
# Use current working directory for development
PRESENTATION_ROOT="$PWD/presentation"
DEMO_ROOT="$PWD/docs/demo"
if [ ! -d "$PRESENTATION_ROOT" ]; then
echo "Error: presentation/ directory not found in current directory"
echo "Please run this command from the project root"
exit 1
fi
if [ ! -d "$DEMO_ROOT" ]; then
echo "Error: docs/demo/ directory not found in current directory"
echo "Please run this command from the project root"
exit 1
fi
# Generate Caddyfiles at runtime
PRESENTATION_CADDY_CONFIG=$(mktemp)
DEMO_CADDY_CONFIG=$(mktemp)
COMPOSE_CONFIG=$(mktemp)
trap "rm -f $PRESENTATION_CADDY_CONFIG $DEMO_CADDY_CONFIG $COMPOSE_CONFIG" EXIT
cat > "$PRESENTATION_CADDY_CONFIG" <<EOF
:8000 {
root * $PRESENTATION_ROOT
file_server browse
encode gzip
log {
output stdout
format console
}
}
EOF
cat > "$DEMO_CADDY_CONFIG" <<EOF
:8001 {
root * $DEMO_ROOT
file_server browse
encode gzip
log {
output stdout
format console
}
}
EOF
# Generate process-compose config at runtime
cat > "$COMPOSE_CONFIG" <<EOF
{
"version": "0.5",
"processes": {
"presentation": {
"command": "${pkgs.caddy}/bin/caddy run --config $PRESENTATION_CADDY_CONFIG --adapter caddyfile",
"readiness_probe": {
"http_get": {
"host": "localhost",
"port": 8000
}
}
},
"conversation": {
"command": "${pkgs.caddy}/bin/caddy run --config $DEMO_CADDY_CONFIG --adapter caddyfile",
"readiness_probe": {
"http_get": {
"host": "localhost",
"port": 8001
}
}
}
}
}
EOF
echo "Starting demo environment:"
echo " - Presentation: http://localhost:8000"
echo " - Conversation: http://localhost:8001"
exec ${pkgs.process-compose}/bin/process-compose up -f "$COMPOSE_CONFIG" --tui=false
''}";
};
});
# Development shells
devShells = forAllSystems (system: pkgs: {
default = pkgs.mkShell {
buildInputs = [
pkgs.caddy
pkgs.process-compose
pkgs.bash
# Optional tools (uncomment as needed)
# pkgs.nodejs
# pkgs.asciinema
# pkgs.bat
# pkgs.alejandra # Nix formatter
];
shellHook = ''
echo "Welcome to 'Beyond the Prompt' development environment!"
echo ""
echo "Available commands:"
echo " nix run .#present - Start presentation server (http://localhost:8000)"
echo " nix run .#demo - Start demo environment (presentation + conversation)"
echo ""
echo "Direct development (with live reload):"
echo " caddy file-server --root ./presentation --listen :8000"
echo ""
echo "Project structure:"
echo " docs/adr/ - Architecture Decision Records"
echo " presentation/ - Reveal.js presentation files"
echo " docs/demo/ - Conversation transcript and demo materials"
echo ""
'';
};
});
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View file

@ -0,0 +1,283 @@
@import url(https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap);
@import url(https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap);
/* Nix Blue Theme for Remark - Optimized for 100" at 15ft */
body {
font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
font-size: 38px;
color: #2c3e50;
background: white !important;
}
.remark-notes-preview-area {
display: none;
}
.remark-notes {
height: 100vw;
}
.remark-slide-scaler {
background: white !important;
}
.remark-slide-container {
background: white !important;
}
.remark-slide-content {
background: white !important;
padding: 40px 80px 60px 80px;
}
/* Headings */
h1 {
font-size: 3em;
font-weight: 700;
color: #5277c3;
margin-bottom: 0.5em;
border-bottom: 4px solid #5277c3;
padding-bottom: 0.3em;
}
h2 {
font-size: 2.5em;
font-weight: 700;
color: #5277c3;
margin-bottom: 0.5em;
border-bottom: 3px solid #5277c3;
padding-bottom: 0.2em;
}
h3 {
font-size: 2em;
font-weight: 600;
color: #5277c3;
margin-bottom: 0.4em;
}
/* Text */
p {
line-height: 1.5;
margin: 0.6em 0;
}
/* Lists */
ul, ol {
line-height: 1.6;
margin: 0.8em 0;
}
li {
margin: 0.5em 0;
}
/* Links */
a {
color: #7ebae4;
text-decoration: none;
border-bottom: 2px solid transparent;
transition: border-color 0.2s;
}
a:hover {
border-bottom-color: #5277c3;
}
/* Code */
.remark-code, .remark-inline-code {
font-family: 'Fira Code', 'Monaco', monospace;
}
.remark-inline-code {
background: #f8f9fa;
color: #5277c3;
padding: 0.2em 0.4em;
border-radius: 3px;
font-size: 0.9em;
}
.remark-code {
font-size: 0.75em;
line-height: 1.5;
}
pre {
background: #f8f9fa;
border: 2px solid #e9ecef;
border-radius: 6px;
padding: 1.2em;
margin: 1em 0;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05);
}
/* Tables */
table {
border-collapse: collapse;
width: 100%;
margin: 1em 0;
font-size: 0.9em;
}
th {
background: #5277c3;
color: white;
padding: 0.6em;
text-align: left;
font-weight: 600;
}
td {
padding: 0.6em;
border-bottom: 1px solid #e9ecef;
}
tr:hover {
background: #f8f9fa;
}
/* Blockquotes */
blockquote {
border-left: 5px solid #5277c3;
padding-left: 1.5em;
margin: 1em 0;
font-style: italic;
color: #666;
}
/* Strong/Bold */
strong {
font-weight: 700;
color: #5277c3;
}
/* Emphasis/Italic */
em {
font-style: italic;
color: #666;
}
/* Slide number */
.remark-slide-number {
font-size: 0.6em;
color: #999;
opacity: 0.6;
}
/* Footnotes */
.footnote {
position: absolute;
bottom: 3em;
font-size: 0.7em;
color: #999;
}
/* Center and middle classes */
.center {
text-align: center;
}
.middle {
vertical-align: middle;
}
/* Two column layout */
.left-column {
width: 48%;
float: left;
}
.right-column {
width: 48%;
float: right;
}
/* Incremental reveal styling */
.remark-visible {
opacity: 1;
}
.remark-invisible {
opacity: 0;
}
/* Syntax highlighting - light theme to match pre blocks */
.hljs {
background: #f8f9fa !important;
color: #2c3e50 !important;
padding: 1.2em !important;
border-radius: 6px;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal {
color: #5277c3 !important;
font-weight: 600;
}
.hljs-string,
.hljs-title,
.hljs-section {
color: #0d6efd !important;
}
.hljs-type,
.hljs-class .hljs-title {
color: #198754 !important;
}
.hljs-number,
.hljs-regexp,
.hljs-link {
color: #d63384 !important;
}
.hljs-comment {
color: #6c757d !important;
font-style: italic;
}
/* Checkmarks and X marks */
.remark-slide-content li::before {
content: none;
}
/* Special styling for centered slides */
.remark-slide-content.center.middle {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.remark-slide-content.center.middle h1 {
border-bottom: none;
margin-bottom: 0.3em;
}
/* Image styling */
img {
max-width: 100%;
height: auto;
border-radius: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
/* Presenter notes styling */
.remark-notes {
font-size: 26px;
}
/* Print styles */
@media print {
.remark-slide-scaler {
width: 100% !important;
height: 100% !important;
transform: scale(1) !important;
top: 0 !important;
left: 0 !important;
}
}

View file

@ -0,0 +1,171 @@
/* High Contrast Theme - Bold storytelling with visual pop */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
font-size: 44px;
font-weight: 400;
color: #1a1a1a;
background: white !important;
}
.remark-slide-scaler, .remark-slide-container {
background: white !important;
}
.remark-slide-content {
background: white !important;
padding: 90px 110px;
}
/* Bold headings with color accents */
h1 {
font-size: 4.5em;
font-weight: 700;
color: #0066ff;
margin: 0 0 0.2em 0;
line-height: 1;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.8em;
font-weight: 600;
color: #1a1a1a;
margin: 0.4em 0;
line-height: 1.1;
}
h3 {
font-size: 2em;
font-weight: 600;
color: #666;
margin: 0.5em 0;
}
/* Regular text */
p {
font-weight: 400;
line-height: 1.5;
margin: 1em 0;
}
/* Strong emphasis in accent color */
strong {
font-weight: 700;
color: #0066ff;
}
/* Questions get special treatment */
p:has(strong:first-child) {
font-size: 1.2em;
margin: 1.5em 0;
}
/* Code with accent border */
code {
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Courier New', monospace;
background: #f0f7ff;
color: #0066ff;
padding: 0.15em 0.4em;
border-radius: 3px;
font-size: 0.85em;
font-weight: 600;
}
pre {
background: #1a1a1a;
color: #fff;
padding: 1.8em;
margin: 1.5em 0;
font-size: 0.7em;
line-height: 1.6;
border-radius: 8px;
}
pre code {
background: none;
color: #fff;
padding: 0;
}
/* Lists with accent bullets */
ul, ol {
margin: 1.5em 0;
padding-left: 0;
}
li {
margin: 0.9em 0;
line-height: 1.5;
padding-left: 2em;
position: relative;
}
ul li::before {
content: "▸";
position: absolute;
left: 0;
color: #0066ff;
font-size: 1.2em;
font-weight: 700;
}
/* Blockquotes with accent */
blockquote {
border-left: 8px solid #0066ff;
padding-left: 2em;
margin: 2em 0;
font-size: 1.3em;
color: #333;
font-style: italic;
}
/* Center slides */
.remark-slide-content.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
/* Tables */
table {
width: 100%;
margin: 2em 0;
font-size: 0.8em;
border-collapse: collapse;
}
th {
background: #0066ff;
color: white;
padding: 0.8em;
text-align: left;
font-weight: 600;
}
td {
padding: 0.8em;
border-bottom: 1px solid #e0e0e0;
}
tr:hover {
background: #f0f7ff;
}
/* Slide numbers */
.remark-slide-number {
font-size: 0.5em;
color: #ccc;
}
/* Footnotes */
.footnote {
position: absolute;
bottom: 3em;
font-size: 0.6em;
color: #999;
}

View file

@ -0,0 +1,137 @@
/* Minimal Theme - Ultra-clean, maximum focus */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
font-size: 48px;
font-weight: 300;
color: #000;
background: white !important;
}
.remark-slide-scaler, .remark-slide-container {
background: white !important;
}
.remark-slide-content {
background: white !important;
padding: 100px 120px;
}
/* Massive, single-focus headings */
h1 {
font-size: 5em;
font-weight: 600;
color: #000;
margin: 0;
line-height: 1;
letter-spacing: -0.03em;
}
h2 {
font-size: 3em;
font-weight: 300;
color: #666;
margin: 0.3em 0 0 0;
line-height: 1.1;
}
h3 {
font-size: 2em;
font-weight: 400;
color: #999;
margin: 0.5em 0;
}
/* Ultra-light body text */
p {
font-weight: 300;
line-height: 1.7;
margin: 1.5em 0;
max-width: 85%;
}
strong {
font-weight: 600;
color: #000;
}
/* Questions in larger, lighter font */
p strong:first-child {
font-size: 1.2em;
font-weight: 400;
display: block;
margin-bottom: 0.5em;
}
/* Code - monochrome */
code {
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Courier New', monospace;
background: #f5f5f5;
padding: 0.2em 0.4em;
font-size: 0.8em;
color: #000;
}
pre {
background: #f5f5f5;
padding: 2em;
margin: 2em 0;
font-size: 0.65em;
line-height: 1.6;
}
pre code {
background: none;
padding: 0;
}
/* Lists - maximum breathing room */
ul, ol {
margin: 2em 0;
padding: 0;
list-style: none;
}
li {
margin: 1.2em 0;
line-height: 1.6;
padding-left: 2em;
position: relative;
}
li::before {
content: "•";
position: absolute;
left: 0;
font-size: 0.8em;
color: #ccc;
}
/* Center slides - full focus */
.remark-slide-content.center {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
}
.remark-slide-content.center p {
max-width: 100%;
}
/* Hide everything except essentials */
.remark-slide-number {
display: none;
}
blockquote {
border: none;
padding: 0;
margin: 2em 0;
font-size: 1.5em;
font-weight: 300;
color: #666;
font-style: normal;
}

View file

@ -0,0 +1,208 @@
/* Modern Storytelling Theme - Clean, bold, narrative-focused */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
font-size: 42px;
font-weight: 300;
color: #1a1a1a;
background: white !important;
}
.remark-slide-scaler {
background: white !important;
}
.remark-slide-container {
background: white !important;
}
.remark-slide-content {
background: white !important;
padding: 80px 100px;
}
/* Large impactful headings */
h1 {
font-size: 4em;
font-weight: 700;
color: #000;
margin: 0;
line-height: 1.1;
letter-spacing: -0.02em;
}
h2 {
font-size: 2.5em;
font-weight: 600;
color: #333;
margin: 0.5em 0;
line-height: 1.2;
}
h3 {
font-size: 1.8em;
font-weight: 600;
color: #555;
margin: 0.5em 0;
}
/* Light body text */
p {
font-weight: 300;
line-height: 1.6;
margin: 1em 0;
}
/* Emphasis */
strong {
font-weight: 700;
color: #000;
}
em {
font-style: italic;
color: #666;
}
/* Questions stand out */
.remark-slide-content p:has(strong:contains("Question")),
.remark-slide-content p:has(strong:contains("Quick poll")),
.remark-slide-content p:has(strong:contains("Show of hands")) {
font-size: 1.3em;
font-weight: 600;
color: #2563eb;
margin: 1.5em 0;
}
/* Incremental reveals - subtle */
.remark-visible {
opacity: 1;
}
/* Code - minimal distraction */
code {
font-family: 'SF Mono', Monaco, 'Cascadia Code', 'Courier New', monospace;
background: #f8f9fa;
padding: 0.1em 0.4em;
border-radius: 4px;
font-size: 0.85em;
color: #e63946;
}
pre {
background: #f8f9fa;
border-left: 4px solid #e63946;
padding: 1.5em;
margin: 1.5em 0;
font-size: 0.7em;
line-height: 1.5;
}
pre code {
background: none;
padding: 0;
color: #333;
}
/* Lists - clean and spacious */
ul, ol {
margin: 1.5em 0;
padding-left: 1.5em;
}
li {
margin: 0.8em 0;
line-height: 1.5;
}
/* Remove default bullets, use em dash */
ul li {
list-style: none;
position: relative;
}
ul li::before {
content: "—";
position: absolute;
left: -1.5em;
color: #e63946;
font-weight: 700;
}
/* Blockquotes for emphasis */
blockquote {
border-left: 6px solid #e63946;
padding-left: 2em;
margin: 2em 0;
font-size: 1.2em;
font-weight: 300;
font-style: italic;
color: #555;
}
/* Center content for dramatic effect */
.remark-slide-content.center {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.remark-slide-content.center h1 {
margin-bottom: 0.3em;
}
.remark-slide-content.center h2 {
font-weight: 400;
color: #666;
}
/* Accent color for key moments */
.accent {
color: #e63946;
font-weight: 700;
}
/* Tables - minimal */
table {
width: 100%;
border-collapse: collapse;
margin: 2em 0;
font-size: 0.8em;
}
th {
background: #f8f9fa;
padding: 0.8em;
text-align: left;
font-weight: 600;
border-bottom: 3px solid #e63946;
}
td {
padding: 0.8em;
border-bottom: 1px solid #e9ecef;
}
/* Slide numbers - subtle */
.remark-slide-number {
font-size: 0.5em;
color: #ccc;
opacity: 0.5;
}
/* Footnotes */
.footnote {
position: absolute;
bottom: 3em;
font-size: 0.6em;
color: #999;
}
/* Speaker notes hidden in presentation */
.remark-notes {
display: none;
}

View file

@ -0,0 +1,315 @@
/* Updated: Centering fix v2 */
/* Theme 1: Terminal Dark (Default) - Hacker aesthetic */
.reveal.theme-terminal {
--r-background-color: #0d1117;
--r-main-font: 'Monaco', 'Courier New', monospace;
--r-heading-font: 'Monaco', 'Courier New', monospace;
--r-main-color: #58a6ff;
--r-heading-color: #8ce99a;
--r-link-color: #79c0ff;
--r-link-color-hover: #a5d6ff;
--r-selection-background-color: #1f6feb;
--r-code-font: 'Monaco', monospace;
}
.reveal.theme-terminal .slides section {
border: 2px solid #30363d;
background: rgba(13, 17, 23, 0.95);
}
.reveal.theme-terminal h1::before,
.reveal.theme-terminal h2::before {
content: '> ';
color: #8ce99a;
}
.reveal.theme-terminal pre {
background: #161b22;
border: 1px solid #30363d;
}
.reveal.theme-terminal code {
background: #161b22;
color: #c9d1d9;
}
/* Theme 2: Nix Blue - Clean and professional */
.reveal.theme-nix {
--r-background-color: #f5f7fa;
--r-main-font: 'Inter', 'Segoe UI', system-ui, sans-serif;
--r-heading-font: 'Inter', 'Segoe UI', system-ui, sans-serif;
--r-main-color: #2c3e50;
--r-heading-color: #5277c3;
--r-link-color: #7ebae4;
--r-link-color-hover: #5277c3;
--r-selection-background-color: #5277c3;
--r-code-font: 'Fira Code', monospace;
}
.reveal.theme-nix {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.reveal.theme-nix .slides section {
background: white;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
border-radius: 8px;
}
.reveal.theme-nix h1,
.reveal.theme-nix h2 {
font-weight: 700;
border-bottom: 3px solid #5277c3;
padding-bottom: 0.3em;
}
.reveal.theme-nix pre {
background: #f8f9fa;
border: 2px solid #e9ecef;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.05);
}
.reveal.theme-nix code {
background: #f8f9fa;
color: #5277c3;
}
/* Theme 3: Solarized Light - Easy on the eyes */
.reveal.theme-solarized {
--r-background-color: #fdf6e3;
--r-main-font: 'Source Sans Pro', sans-serif;
--r-heading-font: 'Source Sans Pro', sans-serif;
--r-main-color: #657b83;
--r-heading-color: #268bd2;
--r-link-color: #2aa198;
--r-link-color-hover: #859900;
--r-selection-background-color: #eee8d5;
--r-code-font: 'Source Code Pro', monospace;
}
.reveal.theme-solarized .slides section {
background: #fdf6e3;
border: 1px solid #eee8d5;
}
.reveal.theme-solarized pre {
background: #eee8d5;
border: 1px solid #d3cbb7;
}
.reveal.theme-solarized code {
background: #eee8d5;
color: #268bd2;
padding: 0.2em 0.4em;
border-radius: 3px;
}
/* Theme 4: Dracula - Vibrant dark mode */
.reveal.theme-dracula {
--r-background-color: #282a36;
--r-main-font: 'Helvetica Neue', Helvetica, sans-serif;
--r-heading-font: 'Helvetica Neue', Helvetica, sans-serif;
--r-main-color: #f8f8f2;
--r-heading-color: #ff79c6;
--r-link-color: #8be9fd;
--r-link-color-hover: #50fa7b;
--r-selection-background-color: #44475a;
--r-code-font: 'Fira Code', monospace;
}
.reveal.theme-dracula {
background: linear-gradient(135deg, #282a36 0%, #44475a 100%);
}
.reveal.theme-dracula h1,
.reveal.theme-dracula h2 {
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
}
.reveal.theme-dracula pre {
background: #1e1f29;
border: 1px solid #44475a;
}
.reveal.theme-dracula code {
background: #44475a;
color: #50fa7b;
padding: 0.2em 0.4em;
border-radius: 3px;
}
/* Theme 5: Nord - Minimalist arctic */
.reveal.theme-nord {
--r-background-color: #2e3440;
--r-main-font: 'Roboto', sans-serif;
--r-heading-font: 'Roboto Slab', serif;
--r-main-color: #eceff4;
--r-heading-color: #88c0d0;
--r-link-color: #81a1c1;
--r-link-color-hover: #5e81ac;
--r-selection-background-color: #4c566a;
--r-code-font: 'JetBrains Mono', monospace;
}
.reveal.theme-nord .slides section {
background: rgba(46, 52, 64, 0.95);
border-left: 4px solid #88c0d0;
}
.reveal.theme-nord pre {
background: #3b4252;
border: 1px solid #4c566a;
}
.reveal.theme-nord code {
background: #3b4252;
color: #8fbcbb;
}
.reveal.theme-nord .fragment.highlight-current-blue.current-fragment {
color: #88c0d0;
}
.reveal.theme-nord strong {
color: #88c0d0;
}
/* Theme selector UI - Floating overlay */
#theme-selector {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
background: rgba(0, 0, 0, 0.85);
padding: 12px 18px;
border-radius: 10px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.1);
pointer-events: auto;
backdrop-filter: blur(15px);
-webkit-backdrop-filter: blur(15px);
transition: all 0.3s ease;
isolation: isolate;
}
#theme-selector:hover {
background: rgba(0, 0, 0, 0.95);
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(255, 255, 255, 0.2);
}
/* Ensure theme selector doesn't interfere with presentation */
body {
margin: 0;
padding: 0;
}
.reveal {
pointer-events: auto;
}
#theme-selector label {
color: rgba(255, 255, 255, 0.9);
font-size: 13px;
margin-right: 10px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
font-weight: 500;
letter-spacing: 0.3px;
}
#theme-selector select {
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(255, 255, 255, 0.2);
padding: 7px 14px;
border-radius: 6px;
font-size: 13px;
cursor: pointer;
outline: none;
transition: all 0.3s ease;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
font-weight: 500;
}
#theme-selector select:hover {
background: white;
border-color: rgba(88, 166, 255, 0.5);
}
#theme-selector select:focus {
box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.4);
border-color: rgba(88, 166, 255, 0.8);
}
/* Adaptive styling based on presentation theme */
.reveal.has-dark-background ~ #theme-selector {
background: rgba(0, 0, 0, 0.85);
}
.reveal.has-light-background ~ #theme-selector {
background: rgba(0, 0, 0, 0.75);
}
/* Large screen readability - 100" at 15 feet */
.reveal {
font-size: 38px;
}
.reveal h1 {
font-size: 2.5em;
font-weight: 700;
margin-bottom: 0.5em;
}
.reveal h2 {
font-size: 2em;
font-weight: 700;
margin-bottom: 0.5em;
}
.reveal h3 {
font-size: 1.5em;
margin-bottom: 0.4em;
}
.reveal p {
line-height: 1.5;
margin: 0.5em 0;
}
.reveal li {
margin: 0.4em 0;
line-height: 1.5;
}
.reveal ul, .reveal ol {
text-align: left;
}
.reveal pre {
font-size: 0.65em;
}
.reveal code {
font-size: 0.9em;
}
.reveal small {
font-size: 0.7em;
}
/* Responsive adjustments */
@media (max-width: 768px) {
#theme-selector {
top: 10px;
right: 10px;
padding: 8px;
}
#theme-selector label {
display: none;
}
#theme-selector select {
font-size: 12px;
padding: 4px 8px;
}
}

101
presentation/index.html Normal file
View file

@ -0,0 +1,101 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beyond the Prompt: Lessons from Building with Claude Code by Scott Scoble</title>
<link rel="stylesheet" href="assets/remark-theme.css">
<meta name="author" content="Scott Scoble">
</head>
<body>
<script src="vendor/remark.min.js"></script>
<script>
var slideshow = remark.create({
sourceUrl: 'slides.md',
highlightStyle: 'monokai',
highlightLines: true,
highlightSpans: true,
ratio: '16:9',
navigation: {
scroll: false,
touch: true,
click: false
}
});
// Enhanced presenter mode with separate window control
var presenterWindow = null;
// Listen for 'S' key to open separate presenter window
document.addEventListener('keydown', function(e) {
if (e.key === 's' || e.key === 'S') {
if (!presenterWindow || presenterWindow.closed) {
// Open presenter window
presenterWindow = window.open(
window.location.href + '?presenter=true',
'presenter',
'width=1200,height=800'
);
}
}
});
// Check if this is the presenter window
const urlParams = new URLSearchParams(window.location.search);
const isPresenter = urlParams.get('presenter') === 'true';
if (isPresenter) {
// Enable built-in presenter mode for this window
document.addEventListener('DOMContentLoaded', function() {
slideshow.gotoSlide(slideshow.getCurrentSlideIndex());
});
// Auto-trigger presenter mode
setTimeout(function() {
// Simulate 'p' keypress for presenter mode
var event = new KeyboardEvent('keydown', { key: 'p' });
document.dispatchEvent(event);
}, 500);
}
// Synchronize slides between windows using localStorage
slideshow.on('showSlide', function(slide) {
if (!isPresenter) {
// Main window broadcasts slide changes
localStorage.setItem('current-slide', slide.getSlideIndex());
}
});
// Listen for slide changes from main window (if presenter)
if (isPresenter) {
window.addEventListener('storage', function(e) {
if (e.key === 'current-slide') {
var slideIndex = parseInt(e.newValue);
if (slideshow.getCurrentSlideIndex() !== slideIndex) {
slideshow.gotoSlide(slideIndex);
}
}
});
}
// Display keyboard shortcuts on '?'
document.addEventListener('keydown', function(e) {
if (e.key === '?') {
alert(
'Keyboard Shortcuts:\n\n' +
'Arrow keys / Space: Navigate slides\n' +
'S: Open separate presenter window\n' +
'P: Toggle presenter mode (current window)\n' +
'C: Clone presentation\n' +
'F: Fullscreen\n' +
'?: Show this help'
);
}
});
</script>
<p style="position:fixed;bottom:10px;right:20px;font-size:12px;color:#888;z-index:9999;background:rgba(0,0,0,0.5);padding:4px 10px;border-radius:4px;">
A presentation by <a href="https://scott.scoble.me" style="color:#4ae64a;">Scott Scoble</a>
</p>
</body>
</html>

View file

@ -0,0 +1,204 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Beyond the Prompt: Lessons from Building with Claude Code</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/dist/reveal.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/dist/theme/black.css" id="theme-base">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/plugin/highlight/monokai.css">
<link rel="stylesheet" href="assets/themes.css">
</head>
<body>
<div class="reveal theme-nix">
<div class="slides">
<section>
<h1>Beyond the Prompt</h1>
<h3>Lessons from Building with Claude Code</h3>
<p>
<small>Using ADRs to Guide AI-Assisted Development</small>
</p>
</section>
<section>
<h2>The Challenge</h2>
<p>How do you effectively delegate complex development tasks to an AI assistant?</p>
<ul>
<li class="fragment">Vague prompts → unpredictable results</li>
<li class="fragment">No architectural context → poor decisions</li>
<li class="fragment">Iterative refinement → lost in conversation</li>
</ul>
</section>
<section>
<h2>The Solution: ADRs</h2>
<p><strong>Architecture Decision Records</strong></p>
<ul>
<li class="fragment">Document <em>why</em> decisions were made</li>
<li class="fragment">Provide clear constraints and boundaries</li>
<li class="fragment">Enable iterative refinement with context</li>
<li class="fragment">Create a shared understanding with AI</li>
</ul>
</section>
<section>
<h2>ADR Structure</h2>
<pre><code data-trim data-noescape>
## Status
Proposed | Accepted | Deprecated | Superseded
## Context
The problem or situation requiring a decision
## Decision
What was decided
## Rationale
Why this decision (including alternatives considered)
## Consequences
Positive, negative, and mitigations
</code></pre>
</section>
<section>
<h2>Case Study: This Presentation</h2>
<p class="fragment">This entire presentation system was built using the ADR-driven approach</p>
<p class="fragment"><strong>The demo IS the conversation that built it</strong></p>
</section>
<section>
<h2>ADR 001: Presentation Tech</h2>
<ul>
<li><strong>Decision</strong>: Reveal.js</li>
<li><strong>Why</strong>: Static HTML/JS, no build process, Nix-friendly</li>
<li><strong>Alternatives</strong>: Marp (too limiting), Slidev (complex), Beamer (wrong format)</li>
</ul>
</section>
<section>
<h2>ADR 002: Infrastructure</h2>
<ul>
<li><strong>Decision</strong>: Caddy + process-compose</li>
<li><strong>Why</strong>: Configuration as code, orchestration, monitoring</li>
<li><strong>Constraint Applied</strong>: "No Python" → rearchitecture</li>
</ul>
</section>
<section>
<h2>The Iterative Process</h2>
<ol>
<li class="fragment">Initial ADR: Python HTTP server</li>
<li class="fragment">Constraint: "Python is verboten"</li>
<li class="fragment">Refinement: Evaluated alternatives (darkhttpd, miniserve, caddy)</li>
<li class="fragment">Evolution: Added process-compose for orchestration</li>
<li class="fragment">Result: Better architecture from constraints</li>
</ol>
</section>
<section>
<h2>ADR 003: The Meta Twist</h2>
<p><strong>Decision</strong>: The demo is the conversation itself</p>
<ul>
<li class="fragment">Authentic: Real Claude Code usage</li>
<li class="fragment">Educational: Shows thinking process</li>
<li class="fragment">Reproducible: Pattern is learnable</li>
<li class="fragment">Meta: This ADR documents itself as the demo</li>
</ul>
</section>
<section>
<h2>Key Patterns</h2>
<ul>
<li><strong>Use ADRs for context</strong> - Document decisions, not just code</li>
<li><strong>Apply constraints iteratively</strong> - Better design emerges</li>
<li><strong>Embrace refinement</strong> - First solution rarely perfect</li>
<li><strong>Configuration as code</strong> - Generate, don't write manually</li>
</ul>
</section>
<section>
<h2>The Implementation</h2>
<pre><code class="language-nix" data-trim>
{
apps.present = {
type = "app";
program = writeScript "present" ''
caddy_config=${makeCaddyConfig 8000 presentation}
compose_config=${makeProcessComposeConfig {...}}
exec process-compose up -f "$compose_config"
'';
};
}
</code></pre>
<p class="fragment"><small>Configuration generated from Nix expressions</small></p>
</section>
<section>
<h2>View the Conversation</h2>
<p>The actual development conversation is available at:</p>
<p><a href="http://localhost:8001">http://localhost:8001</a></p>
<p class="fragment"><small>(When running <code>nix run .#demo</code>)</small></p>
</section>
<section>
<h2>Takeaways</h2>
<ol>
<li class="fragment"><strong>ADRs provide boundaries</strong> - Guide AI with context</li>
<li class="fragment"><strong>Constraints improve design</strong> - Limitations force creativity</li>
<li class="fragment"><strong>Conversations are artifacts</strong> - Document the journey</li>
<li class="fragment"><strong>Meta-awareness helps</strong> - Use the tool to understand the tool</li>
</ol>
</section>
<section>
<h2>Try It Yourself</h2>
<pre><code class="language-bash" data-trim>
# Clone the repository
git clone [repo-url]
# Enter development environment
nix develop
# Run the presentation
nix run .#present
# Run the full demo
nix run .#demo
</code></pre>
</section>
<section>
<h2>Resources</h2>
<ul>
<li>ADRs in <code>docs/adr/</code></li>
<li>Conversation transcript in <code>docs/demo/</code></li>
<li>Implementation in <code>flake.nix</code></li>
<li>Git history shows evolution</li>
</ul>
</section>
<section>
<h1>Thank You</h1>
<p>Questions?</p>
<br>
<p><small>This presentation was built with Claude Code using the techniques described</small></p>
</section>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/dist/reveal.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/plugin/notes/notes.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/plugin/markdown/markdown.js"></script>
<script src="https://cdn.jsdelivr.net/npm/reveal.js@5.0.4/plugin/highlight/highlight.js"></script>
<script>
// Initialize Reveal.js
Reveal.initialize({
hash: true,
plugins: [ RevealMarkdown, RevealHighlight, RevealNotes ],
transition: 'slide',
backgroundTransition: 'fade'
});
</script>
</body>
</html>

234
presentation/print.html Normal file
View file

@ -0,0 +1,234 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Beyond the Prompt - Printable Version</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap');
@page {
size: letter;
margin: 0.75in;
}
body {
font-family: 'Inter', sans-serif;
font-size: 11pt;
line-height: 1.5;
color: #2c3e50;
max-width: 100%;
}
.slide {
page-break-after: always;
margin-bottom: 2em;
border-bottom: 3px solid #5277c3;
padding-bottom: 1em;
}
.slide-header {
background: #5277c3;
color: white;
padding: 0.5em 1em;
margin: -0.75in -0.75in 1em -0.75in;
font-weight: 700;
}
.slide-content h1 {
color: #5277c3;
font-size: 24pt;
margin-top: 0;
border-bottom: 3px solid #5277c3;
padding-bottom: 0.25em;
}
.slide-content h2 {
color: #5277c3;
font-size: 18pt;
margin-top: 0.5em;
}
.slide-content h3 {
color: #5277c3;
font-size: 14pt;
}
.slide-content p {
margin: 0.75em 0;
}
.slide-content ul, .slide-content ol {
margin: 0.75em 0;
padding-left: 2em;
}
.slide-content li {
margin: 0.5em 0;
}
.slide-content code {
font-family: 'Fira Code', monospace;
background: #f8f9fa;
padding: 0.1em 0.3em;
border-radius: 3px;
font-size: 10pt;
}
.slide-content pre {
background: #f8f9fa;
border: 1px solid #e9ecef;
border-radius: 4px;
padding: 1em;
overflow-x: auto;
font-size: 9pt;
}
.slide-content pre code {
background: none;
padding: 0;
}
.speaker-notes {
background: #f8f9fa;
border-left: 2px solid #5277c3;
padding: 0.4em 0.6em;
margin-top: 0.5em;
font-size: 7pt;
font-style: italic;
color: #666;
line-height: 1.3;
}
.speaker-notes-header {
font-weight: 600;
color: #5277c3;
font-style: normal;
margin-bottom: 0.25em;
font-size: 7pt;
}
.speaker-notes p {
margin: 0.25em 0;
font-size: 7pt;
}
.incremental {
margin-left: 2em;
color: #666;
}
.incremental::before {
content: "→ ";
color: #5277c3;
}
blockquote {
border-left: 4px solid #5277c3;
padding-left: 1em;
margin: 1em 0;
font-style: italic;
color: #666;
}
strong {
color: #5277c3;
font-weight: 700;
}
table {
border-collapse: collapse;
width: 100%;
margin: 1em 0;
font-size: 10pt;
}
th {
background: #5277c3;
color: white;
padding: 0.5em;
text-align: left;
}
td {
padding: 0.5em;
border-bottom: 1px solid #e9ecef;
}
@media print {
.slide {
page-break-after: always;
}
.slide-header {
margin: 0;
margin-bottom: 1em;
}
}
</style>
</head>
<body>
<script>
// Fetch and parse the markdown
fetch('slides.md')
.then(response => response.text())
.then(markdown => {
const slides = markdown.split(/\n---\n/);
const container = document.body;
slides.forEach((slide, index) => {
const parts = slide.split(/\n\?\?\?\n/);
const content = parts[0].trim();
const notes = parts[1] ? parts[1].trim() : '';
const slideDiv = document.createElement('div');
slideDiv.className = 'slide';
const header = document.createElement('div');
header.className = 'slide-header';
header.textContent = `Slide ${index + 1}`;
slideDiv.appendChild(header);
const slideContent = document.createElement('div');
slideContent.className = 'slide-content';
// Parse markdown content
let html = content
.replace(/^class: center, middle$/gm, '<div style="text-align: center;">')
.replace(/^--$/gm, '<div class="incremental">')
.replace(/^# (.*$)/gm, '<h1>$1</h1>')
.replace(/^## (.*$)/gm, '<h2>$1</h2>')
.replace(/^### (.*$)/gm, '<h3>$1</h3>')
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
.replace(/`([^`]+)`/g, '<code>$1</code>')
.replace(/^- (.*$)/gm, '<li>$1</li>')
.replace(/^(\d+)\. (.*$)/gm, '<li>$2</li>')
.replace(/^> (.*$)/gm, '<blockquote>$1</blockquote>')
.replace(/```(\w*)\n([\s\S]*?)```/g, '<pre><code>$2</code></pre>')
.replace(/\n\n/g, '</p><p>');
// Wrap li in ul
html = html.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');
slideContent.innerHTML = '<p>' + html + '</p>';
slideDiv.appendChild(slideContent);
if (notes) {
const notesDiv = document.createElement('div');
notesDiv.className = 'speaker-notes';
notesDiv.innerHTML = '<div class="speaker-notes-header">Speaker Notes:</div>' +
notes.replace(/\n\n/g, '</p><p>').replace(/^/, '<p>').replace(/$/, '</p>');
slideDiv.appendChild(notesDiv);
}
container.appendChild(slideDiv);
});
// Auto-print after a short delay
setTimeout(() => {
window.print();
}, 1000);
});
</script>
</body>
</html>

987
presentation/slides.md Normal file
View file

@ -0,0 +1,987 @@
class: center, middle
# Beyond the Prompt
## Lessons from Building with Claude Code
???
⏱️ TIME: 0:00 - 0:30 (0.5 min)
Thanks for coming.
This is a true story from the FLUO project - a behavioral assurance platform for OpenTelemetry. The names haven't been changed because I am not innocent.
---
# Who Am I?
<img src="assets/images/onebrief-careers.png" style="position: absolute; bottom: 60px; left: 100px; width: 240px; height: 240px; object-fit: cover;">
<img src="assets/images/profile.jpg" style="position: absolute; bottom: 60px; right: 100px; width: 340px; height: 340px; border-radius: 50%; object-fit: cover;">
**Scott Scoble**
Senior Software Engineer at Onebrief -- *we're hiring!*
???
⏱️ TIME: 2:00 - 4:00 (2.0 min)
I'm a Sr SWE currently at Onebrief. We're hiring. If you're interested, scan the QR code or go to onebrief dot com. Tell them I sent you when they ask.
--
Building Fluo -- otel traces to behavioral signals
???
I'm building Fluo with Claude Code; a behavioral assurance platform for OpenTelemetry.
--
Building a write only high performance database (no name yet)
???
For Fluo, I'm cooking up a write-only, high performance database built on top of DuckDB and Parquet with some consensus seasoning on top.
---
class: center, middle
<img src="assets/images/scared-diver-diving-into-chaotic-pool--t3chat--1.png" style="position: relative; top: -80px; height: 100vh; object-fit: cover; z-index: 999;" />
???
⏱️ TIME: 4:00 - 4:30 (0.5 min)
Let's dive in.
---
# The Request
"I don't want arbitrary code to run in my JVM."
???
⏱️ TIME: 4:30 - 6:30 (2.0 min)
Over the past few months I've been building FLUO. Users write custom rules using OGNL to match patterns in telemetry traces. But here's the scary part: their code runs in OUR JVM. They could access our database, call our APIs, exfiltrate data.
Remember Log4J?
--
**Quick question**: How many of you have had user code running on your server?
???
How many of you have customer code running on your server?
--
Yeah. That's the problem.
---
# So I Asked Claude Code
"How do we sandbox this?"
???
⏱️ TIME: 6:30 - 8:00 (1.5 min)
I asked Claude how we could have these conditions running inside our JVM through a sandboxing strategy.
--
And that's when I saw Claude auto-compacting our coversation again after only a few minutes.
???
Claude was compacting again; why?
--
**The answer depends on what Claude knows. And space is limited.**
???
Claude could only act on what it knows, but it can't know everything.
---
class: center, middle
# Part 1: The Problem
## Context Window Economics
???
⏱️ TIME: 8:00 - 8:30 (0.5 min)
Let's dive deeper into Claude's context problem.
---
# The Context Window Problem
**Question**: How much documentation does your project have?
???
⏱️ TIME: 8:30 - 11:30 (3.0 min)
How much documentation does your project have? Can it all fit in Claude's context window? How many ADRs?
--
FLUO has 15 ADRs. Plus 10 technical domains. Plus 7 subagent perspectives we need on every decision.
???
FLUO is complex: Nix, Quarkus, React, custom DSL. And we need input from PM, EM, TL, SecOps, SRE, BA, CS on every feature.
--
**If we loaded everything**: 75,000 tokens
???
Traditional approach: load all 15 ADRs. That's 75,000 tokens before writing a single line of code.
Traditional in the sense of the past 6 months or so.
--
Your context window is... gone.
???
The AI can't even start. The context window is full of documentation.
note: ask questions from the group on their documentation excess.
---
# Progressive Disclosure: The Solution
**Level 1**: Metadata (~100 tokens per skill)
```yaml
---
name: security-expert
description: OWASP review, compliance controls
---
```
???
⏱️ TIME: 18:30 - 20:30 (2.0 min)
The solution is called progressive disclosure, and it's built into Anthropic's Skills system.
Level 1: Just metadata. Name and description. About 100 tokens. This is ALWAYS loaded. It's how Claude knows what expertise is available.
---
# Progressive Disclosure: The Solution
**Level 2**: Instructions (~1,000 tokens when triggered)
```markdown
# When to Use
- Code touches authentication
- External API integration
- User input validation needed
```
???
⏱️ TIME: 20:30 - 21:30 (1.0 min)
Level 2: Instructions. The actual "how to" guidance. About 1,000 tokens. Only loads when Claude determines it's relevant to your task.
---
# Progressive Disclosure: The Solution
**Level 3**: Resources (unlimited, on-demand)
```
/skills/security/owasp-checklist.md
/skills/security/threat-models/
```
???
⏱️ TIME: 21:30 - 22:30 (1.0 min)
Level 3: Resources. Detailed checklists, threat models, code examples. Unlimited size. Never loaded into context - accessed on-demand via filesystem.
This three-tier system is why we can have 10 skills, 7 subagents, and still use only 1,700 tokens upfront instead of 75,000.
---
# FLUO's Token Budget
**Traditional (ADRs only)**:
```
75,000 tokens loaded upfront
= Context window exhausted
```
???
⏱️ TIME: 22:30 - 25:30 (3.0 min)
Here's where we started. We loaded all the ADRs upfront and exhausted our token budget. I was compacting every 3 or 4 requests.
--
**With Skills + Subagents**:
```
10 skills × 100 tokens = 1,000 tokens
7 subagents × 100 tokens = 700 tokens
Total: 1,700 tokens metadata
When 2-3 trigger: +3,000 tokens instructions
Total active: ~5,000 tokens
```
???
With Skills and Subagents: 1,700 tokens for all metadata. When 2-3 trigger based on your task, you add about 3,000 more. Total: 5,000 tokens for full guidance.
--
**Result**: 95% token reduction, 97% faster
???
That's a 95% reduction. And because we're not loading massive documents, execution is 97% faster.
But the real win isn't speed. It's preventing waste.
---
# Quick Check
Count your functional docs × 1,500 tokens
--
If >10K, you need this.
--
Now let me show you **why** this matters.
???
⏱️ TIME: 25:30 - 29:30 (4.0 min)
Quick audience check - how big is their documentation? This makes it personal.
If they're over 10K tokens, they have the same problem FLUO had.
Now we go back to the sandboxing story to show how this actually prevented disaster.
---
class: center, middle
# Back to Sandboxing
Remember: user code running in our JVM
???
⏱️ TIME: 29:30 - 32:30 (3.0 min)
We're circling back to the opening problem. The audience remembers the setup.
Now they'll see how the context window solution (Skills + Subagents) saved me from making a terrible decision.
---
class: center, middle
# Part 2: The Pattern
## Building a Dream Team
We're assembling subagents and giving them superpowers (skills)
???
⏱️ TIME: 32:30 - 34:30 (2.0 min)
Now we name the pattern with a relatable metaphor: building a dream team.
Each subagent is like a team member with their own perspective. Skills are their superpowers - the knowledge and constraints they enforce.
The audience has seen the problem (sandboxing), understands the constraint (context windows), and now they'll see the solution: a team of AI agents working together.
Here's how four different subagents each brought their perspective to the table.
---
# The Implementer Speaks
"Use Java SecurityManager. Two weeks, done."
???
⏱️ TIME: 34:30 - 38:30 (4.0 min)
First team member: the implementer. This agent wants to ship fast.
Java SecurityManager. Two-week estimate. Sounds perfect.
--
**Show of hands**: How many would ship this?
???
Ask the audience: would you ship this? Most hands go up. We all want fast solutions.
--
I was ready to.
???
Then reveal: I was ready to. But then another team member spoke up.
Build suspense about what saved us.
---
# The Architect Interrupts
Then the architecture agent spoke up.
???
⏱️ TIME: 38:30 - 43:30 (5.0 min)
The architecture guardian reviews everything against our ADRs. It's relentless.
--
"SecurityManager? **Deprecated in Java 17.**"
???
⏱️ TIME: 38:30 - 43:30 (5.0 min)
It caught something I missed: SecurityManager is deprecated. Removed in Java 21.
???
SecurityManager isn't even available anymore, and it has vulnerabilities.
--
We're using Java 25.
???
Pause here. Let it sink in. The audience gets it: we would have shipped dead code.
The "fast" solution just became the impossible one.
---
# Security Weighs In
"Even if SecurityManager wasn't deprecated..."
"...it's bypassable with reflection."
???
⏱️ TIME: 43:30 - 45:30 (2.0 min)
The security expert is brutal. OWASP compliance is non-negotiable.
SecurityManager has known vulnerabilities. Reflection bypass. No resource limits. A malicious rule could DoS the entire system.
--
"3 out of 10 security rating."
--
**Question**: Would you ship 3/10 security to production?
???
Ask the audience: Would you ship 3/10 security?
The answer is obvious. But here's the thing: I almost did. Because I didn't know.
That's the value of having a security expert review BEFORE writing code.
---
# QA Demands Tests
Testing requirements:
- Attack simulations (reflection bypass)
- Performance regression (<10% overhead)
- Multi-tenant isolation
- Resource exhaustion edge cases
- Concurrency stress tests
--
**Adds 1 week for 95%+ coverage**
???
⏱️ TIME: 45:30 - 46:30 (1.0 min)
The QA expert is fanatical about quality. It doesn't trust any implementation without comprehensive tests.
It defines what testing looks like: Attack simulations trying to bypass each layer. Performance tests to ensure sandboxing doesn't kill throughput. Multi-tenant isolation tests. Resource exhaustion edge cases. Concurrency stress tests.
The implementation specialist is starting to sweat. The product manager hasn't even weighed in yet.
---
# Product Does the Math
**Product Manager evaluates the trade-off**:
--
**Option A: SecurityManager**
```
Timeline: 2 weeks now + 10 weeks rewrite = 12 weeks total
Security: 3/10
Risk: Complete rewrite needed in 6 months
```
???
⏱️ TIME: 46:30 - 51:30 (5.0 min)
Time in AI-speak isn't real; it's relative. Option A looks pretty terrible.
--
**Option B: Capability-based security**
```
Timeline: 6 weeks now + 0 weeks later = 6 weeks total
Security: 10/10
Risk: None (future-proof)
```
???
Half the time and 10/10 security score? Sign me up!
---
# Product Does the Math
**Product Manager evaluates the trade-off**:
> "Ship capability-based security. The 4-week investment now saves 6 weeks later, and we get 10/10 security instead of 3/10."
???
⏱️ TIME: 51:30 - 59:30 (8.0 min)
Finally, the product manager looks at this through the lens of total cost and customer value.
The math is obvious. The 4-week delta upfront saves me 6 weeks of rework. Plus we don't ship a security vulnerability.
Decision made. Ship capability-based security.
---
# The Punchline
So after all that evaluation... how long did it take?
???
⏱️ TIME: 59:30 - 1:06:30 (7.0 min)
So how long did it take this collection of agents to implement the final design?
---
# 3 Days
???
⏱️ TIME: 1:06:30 - 1:11:30 (5.0 min)
Just three days of chats; totalling about 6 hours of my time!
--
The subagents made all the hard decisions. Claude Code just implemented them.
???
The subagents make the hard decisions and explained why. Claude was able to just do the right implementation the first time.
--
They caught:
- Java 17 deprecation
- Security vulnerabilities
- Testing requirements
- Total cost analysis
???
Why so fast? Because all the decisions were made. No backtracking. No "oh wait, this won't work." No rework.
The evaluation took 30 minutes. It prevented 12 weeks of waste.
That's a 2,400x return on time invested.
---
# Next Steps
Start with one skill - pick the constraint AI always violates on your project.
Document it. See what changes.
???
⏱️ TIME: 1:11:30 - 1:15:30 (4.0 min)
Here's your second call to action. Think about your project. What's the one thing AI always gets wrong?
For me, it was suggesting Python dependencies when we wanted pure Nix. For you, it might be "never use eval()", "always validate user input", "follow our naming conventions".
Whatever it is, create a skill for it today. Just one. Put it in a `.skills/` directory. Add YAML frontmatter with a clear description.
Then ask Claude to work on something that would normally violate it. Watch what happens. Claude will follow the skill automatically.
One skill. See how it works. Then expand.
Now let me show you how this pattern prevents waste at scale.
---
class: center, middle
# Part 3: How to Build This
## Specifics, not theory
???
⏱️ TIME: 1:15:30 - 1:17:30 (2.0 min)
We've seen the pattern work. Now let's get specific about how YOU build this for your project.
No more stories. Just concrete steps.
---
# Your Dream Team
**4 Essential Subagents:**
1. **Implementer** - "How do we build this fast?"
2. **Architect** - "Does this fit our principles?"
3. **Security** - "What could go wrong?"
4. **Product** - "Is this worth building?"
--
**Start with 2**: Implementer + one other
???
⏱️ TIME: 1:17:30 - 1:19:30 (2.0 min)
Don't try to build all 4 at once. Start with the implementer (you always need that) plus one other based on your biggest pain point.
If you keep shipping insecure code: add security expert.
If you violate architecture principles: add architect.
If you build features nobody uses: add product manager.
Pick your poison. Start with 2.
---
# Subagent Anatomy
```yaml
---
name: architect
role: Review decisions against ADRs
when: Feature requests, technical decisions
---
# Your Identity
You are an architecture guardian. You enforce our documented principles.
# Your Constraints
- NEVER suggest deprecated technologies
- ALWAYS check compatibility with Java 21
- MUST validate against existing ADRs
# Your Response Format
1. State the architectural principle
2. Explain how the proposal violates/aligns
3. Suggest alternatives if needed
```
???
⏱️ TIME: 1:27:30 - 1:31:30 (4.0 min)
This is what a subagent looks like. Three parts:
1. Metadata: who are you, when do you trigger
2. Identity: your personality and focus
3. Constraints: hard rules you enforce
Keep it under 500 tokens. This loads when needed.
---
# Skill Anatomy
```yaml
---
name: nix-http-server
description: Create HTTP servers for Nix projects
---
# Core Constraint
NEVER suggest Python dependencies.
All deps MUST come from nixpkgs.
# Implementation Pattern
Use Caddy from nixpkgs:
- Generate config with pkgs.writeText
- Use process-compose for orchestration
# Anti-Patterns
❌ python -m http.server
❌ npm http-server (external dependency)
✅ caddy (in nixpkgs)
```
???
Skills are simpler than subagents. They're just knowledge and constraints.
Three sections:
1. Core constraint: the one rule that must never be broken
2. Implementation pattern: how to do it right
3. Anti-patterns: common mistakes to avoid
Under 200 tokens for metadata. Full details load when triggered.
---
# The Evaluation Loop
**Before any feature:**
1. Implementer proposes solution (2 min)
2. Other subagents review (5 min)
3. Conflicts surface early (3 min)
4. Decide: build, redesign, or skip (1 min)
???
This is the specific workflow. Every feature goes through this.
--
**Total: 10 minutes**
**Prevents: days to weeks of waste**
???
Takes 10 minutes. Saves days or weeks.
The key: conflicts surface BEFORE writing code. That's when they're cheap to fix.
After code is written, conflicts are expensive. Sunk cost fallacy kicks in.
---
# Real Numbers from FLUO
**Setup cost**: 3 hours to create 4 subagents + 10 skills
--
**Prevented waste**:
- Sandboxing: 12 weeks (deprecated tech)
- Dark mode: 2 weeks (no customer demand)
- API design: 1 week (security violation)
- Database choice: 3 weeks (wrong scale)
--
**Total saved**: 18 weeks in 3 months
**ROI**: 180x
???
Real numbers. Not hypothetical.
3 hours to set up the dream team and skills.
18 weeks of waste prevented in the first 3 months.
That's 180x return on time invested.
And it compounds. The longer you use it, the more waste you prevent.
---
# FLUO's Results
**Context**: 1,700 tokens (95% reduction)
--
**Waste prevented**:
- Sandboxing: 12 weeks
- Dark mode: 2 weeks
- Dozens of smaller decisions
--
**Speed**: Decisions in minutes, not days
???
Let's look at FLUO's results across the entire project.
Context efficiency: 1,700 tokens for all guidance. 95% reduction. We can add more skills and subagents without hitting context limits.
Waste prevention: The two examples I showed you - sandboxing and dark mode - saved me 14 weeks total. But there were dozens of other decisions where subagents caught issues early or questioned assumptions.
Implementation speed: This might seem counterintuitive, but we shipped faster. Why? Because architectural decisions were made upfront by subagents in minutes, not during implementation through painful refactors. Requirements were clear. Less rework.
The pattern works. Evaluate before execute. Multiple perspectives before any code.
---
# The Pattern
Before building: "Is this worth it?"
Evaluate first. Implement second.
???
Here's your final call to action, and it's the most important one.
Before your next feature request - before you write any code - ask a subagent: "Is this worth building?"
Set up a product-manager subagent. Give it a decision framework like RICE scoring: Reach, Impact, Confidence, Effort.
When a feature request comes in, run the evaluation first. Get the subagent's perspective on customer value, opportunity cost, and strategic fit.
Then decide whether to build it. You'll be shocked how many features fail this test.
Every feature you don't build is time saved for features that matter.
---
# Skills vs Subagents
| Aspect | Skills | Subagents |
|--------|--------|-----------|
| **Purpose** | Technical capabilities | Strategic perspectives |
| **Answer** | "How do we implement X?" | "Should we build X?" |
| **Examples** | nix-http-server, security-owasp | product-manager, tech-lead |
| **Trigger** | Task type (HTTP server needed) | Decision point (evaluate feature) |
| **Output** | Code patterns, anti-patterns | Go/no-go, requirements, risks |
--
**Use both**: Skills for HOW, Subagents for SHOULD
???
Let me clarify the distinction between skills and subagents because they solve different problems.
Skills are technical capabilities. They answer "how do we implement X?" They provide code patterns, anti-patterns, validation scripts.
Subagents are strategic perspectives. They answer "should we build X?" They provide go/no-go decisions, requirements clarification, risk assessment.
Skills trigger based on task type. When you need an HTTP server, the nix-http-server skill triggers.
Subagents trigger at decision points. When evaluating a feature, the product-manager subagent weighs in.
Use both. Skills guide implementation. Subagents guide strategy. Together they prevent waste and ensure quality.
---
# The Three Topics
**1. Context Window Economics**
- Progressive disclosure scales
- 95% token reduction
---
# The Three Topics
**2. Skills + Subagents**
- Skills = HOW to implement
- Subagents = SHOULD we build
---
# The Three Topics
**3. Preventing Waste**
- Evaluate before execute
- Multiple perspectives catch mistakes
???
Let me wrap up by reviewing the three major topics and their CTAs.
Topic 1: Context Window Economics. The problem is finite context. The solution is progressive disclosure. Load metadata for everything, instructions only for relevant skills. CTA: Audit your documentation, migrate to skills if you're over 10K tokens.
Topic 2: Skills + Subagents Pattern. Skills encode technical how. Subagents provide strategic should. Together they guide both implementation and decision-making. CTA: Create one skill for your most-violated constraint today.
Topic 3: Preventing Waste at Scale. The pattern is evaluate before execute. Multiple perspectives catch bad decisions early. CTA: Set up a product-manager subagent and evaluate your next feature before building.
These three topics build on each other. You need context efficiency to have room for multiple perspectives. You need skills and subagents to provide those perspectives. And you use them together to prevent waste.
---
# The Complete Picture
**FluoDSL AST** - what we saved:
???
This entire presentation has been telling one story: the FluoDSL AST decision.
--
**Without subagents**:
- Would have shiped deprecated SecurityManager
- Wasted time trying to make it work
- 3/10 security rating shipped to production
???
Without subagents, we would have shipped Java SecurityManager. Two weeks of work. Looks great. Ships with a 3/10 security rating. Gets completely rewritten 6 months later when we upgrade to Java 21. Total cost: 12 weeks.
--
**With subagents**:
- 30 minutes of evaluation from 4 perspectives
- 3 days (in AI *time*) to implement capability-based security
- 10/10 security rating, future-proof
- Prevented waste of time and tokens
???
With subagents, we spent 30 minutes evaluating from 4 perspectives. Architecture caught the Java 17 deprecation. Security defined the 4-layer model. QA specified comprehensive tests. Product approved the investment to avoid rework.
Implementation took 3 days. We shipped 10/10 security. Future-proof. No rework needed.
---
# The Complete Picture
**The pattern scales**: Apply to every feature, every decision, every architectural choice
???
The pattern scales. Apply it to every feature. Every architectural decision. Every refactor.
Evaluate before execute. Get multiple perspectives before any code.
---
# Questions?
Before I wrap this up, I'd love to hear your questions.
---
# Try It Yourself
**FLUO is open source**: github.com/fluohq/fluo
It's a *work in progress*.
???
FLUO is open source. You can see the exact implementation of this pattern.
--
**What you'll find**:
- `.skills/` - 10 technical skills (Nix, Quarkus, React, DSL, etc.)
- `.subagents/` - 7 strategic perspectives (Product Manager, Engineering Manager, Tech Lead, SecOps, SRE, Business Analyst, Customer Success)
- `docs/adrs/` - Architecture Decision Records (for humans)
- Git history showing Skills + Subagents in action
???
10 skills covering our technical domains. 7 subagents covering strategic perspectives. ADRs documenting the WHY for humans. Git history showing the pattern in action.
---
# Try It Yourself
**FLUO is open source**: github.com/fluohq/fluo
**Start with**:
1. One skill (your most-violated constraint)
2. One subagent (product-manager or tech-lead)
3. One decision (evaluate before building)
???
1. Audit your documentation. If it's over 10K tokens, you have a context window problem. Start migrating to Skills.
2. Create one skill today for the constraint AI always violates. See how it works.
3. Before your next feature, set up a product-manager subagent and evaluate first. Ask "is this worth building?"
These are actionable steps you can take this week. Start small. See results immediately.
Don't try to replicate everything at once. Start small.
One skill for your most-violated constraint. One subagent for decision-making. One feature where you evaluate before building.
See how it works. Expand from there.
You'll never go back to the old way.
---
class: center, middle
# Thank You
<img src="assets/images/wscoble-github.png" style="width: 360px; height: 360px;">
https://github.com/wscoble
.footnote[This presentation built with Skills + Subagents guiding every decision]

94
presentation/vendor/fonts/fonts.css vendored Normal file
View file

@ -0,0 +1,94 @@
@font-face {
font-family: 'Fira Code';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/firacode/v27/uU9eCBsR6Z2vfE9aq3bL0fxyUs4tcw4W_D1sFVc.ttf) format('truetype');
}
@font-face {
font-family: 'IBM Plex Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ibmplexmono/v20/-F63fjptAgt5VM-kVkqdyU8n5ig.ttf) format('truetype');
}
@font-face {
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 300;
font-stretch: normal;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ibmplexsans/v23/zYXGKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1swZSAXcomDVmadSDtFlzAA.ttf) format('truetype');
}
@font-face {
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 400;
font-stretch: normal;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ibmplexsans/v23/zYXGKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1swZSAXcomDVmadSD6llzAA.ttf) format('truetype');
}
@font-face {
font-family: 'IBM Plex Sans';
font-style: normal;
font-weight: 600;
font-stretch: normal;
font-display: swap;
src: url(https://fonts.gstatic.com/s/ibmplexsans/v23/zYXGKVElMYYaJe8bpLHnCwDKr932-G7dytD-Dmu1swZSAXcomDVmadSDNF5zAA.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 300;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuOKfMZg.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfMZg.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuGKYMZg.ttf) format('truetype');
}
@font-face {
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/inter/v20/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYMZg.ttf) format('truetype');
}
@font-face {
font-family: 'Space Grotesk';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj7oUUsj.ttf) format('truetype');
}
@font-face {
font-family: 'Space Grotesk';
font-style: normal;
font-weight: 600;
font-display: swap;
src: url(https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj42Vksj.ttf) format('truetype');
}
@font-face {
font-family: 'Space Grotesk';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/spacegrotesk/v22/V8mQoQDjQSkFtoMM3T6r8E7mF71Q-gOoraIAEj4PVksj.ttf) format('truetype');
}
@font-face {
font-family: 'Space Mono';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(https://fonts.gstatic.com/s/spacemono/v17/i7dPIFZifjKcF5UAWdDRUEY.ttf) format('truetype');
}

18
presentation/vendor/remark.min.js vendored Normal file

File diff suppressed because one or more lines are too long

197
skills/README.md Normal file
View file

@ -0,0 +1,197 @@
# Skills Directory
This directory contains Claude Code skills that provide AI implementation guidance for this project.
## Purpose: AI Context
**Skills are for AI, not humans.** They encode HOW to implement architectural decisions with step-by-step procedures, templates, and validation scripts. Claude Code automatically loads skill metadata and selects relevant skills based on the task.
**For human-readable architectural rationale**, see the `/docs/adr` directory.
## Available Skills
### 1. nix-http-server
**Description**: Create HTTP servers for Nix flake projects. NEVER suggest Python dependencies.
**Use when**: Serving static files, creating dev servers, running multi-service environments.
**Key constraints**:
- All dependencies from nixpkgs only
- Use Caddy, never Python http.server
- Generate configs at runtime for dev flexibility
- Use process-compose for orchestration
**Corresponds to**: ADR 002 (Nix Flake Architecture)
### 2. revealjs-presentation
**Description**: Create and style Reveal.js presentations for technical talks. Optimized for large screens.
**Use when**: Building slide decks, HTML-based presentations, technical talks.
**Key patterns**:
- CDN-hosted Reveal.js (no build process)
- Large screen optimization (38px base font for 100" @ 15ft)
- Custom theme system with CSS variables
- Code highlighting with language-specific classes
**Corresponds to**: ADR 001 (Presentation Technology Choice)
### 3. adr-documentation
**Description**: Create and maintain Architecture Decision Records for human documentation.
**Use when**: Documenting architectural decisions, explaining WHY to team members.
**Key patterns**:
- ADRs are for humans, skills are for AI
- Document rationale and alternatives
- Preserve historical context
- Immutable once accepted (create superseding ADR instead)
**Corresponds to**: ADR 003 (Demo Implementation Strategy)
## How Skills Work
### Progressive Disclosure
Skills use a three-tier loading system:
1. **Metadata** (~100 tokens/skill, always loaded)
- Name and description for discovery
- Claude scans all skills at session start
2. **Instructions** (<5k tokens, loaded when triggered)
- Full SKILL.md content
- Only loaded for relevant skills
3. **Resources** (unlimited, on-demand)
- Scripts, templates, reference files
- Accessed via filesystem when needed
### Context Efficiency
**Traditional approach** (loading ADRs):
```
3 ADRs × 1,500 tokens = 4,500 tokens
Doesn't scale beyond ~10-20 documents
```
**Skills approach**:
```
3 skills × 100 tokens metadata = 300 tokens
+ ~2 triggered skills × 5k instructions = 10,300 tokens total
Scales to 100s of skills
```
## The Skills + ADRs Pattern
```
Architectural Decision
↓
┌────┴────┐
▼ ▼
ADR Skill
(Human) (AI)
↓ ↓
Explains Implements
WHY HOW
```
### Integration Example
**ADR 002**: "Use Caddy for HTTP serving, not Python"
- Location: `docs/adr/002-nix-flake-architecture.md`
- Audience: Human developers
- Purpose: Explain WHY (dependency management, nixpkgs-only)
**Skill**: `nix-http-server`
- Location: `skills/nix-http-server/SKILL.md`
- Audience: Claude AI
- Purpose: Enforce HOW (never suggest Python, use Caddy)
## Creating New Skills
### When to Create a Skill
After writing an ADR, create a skill if:
- [ ] Decision involves repetitive implementation patterns
- [ ] AI should automatically enforce constraints
- [ ] Pattern can be automated with templates/scripts
- [ ] You want perfect consistency
### Skill Structure
```
skills/
└── my-skill/
├── SKILL.md # Required: metadata + instructions
├── scripts/ # Optional: executable scripts
│ └── validate.sh
└── templates/ # Optional: code templates
└── example.template
```
### SKILL.md Format
```markdown
---
name: skill-identifier
description: When to use this skill (max 1024 chars). Be specific about triggers.
---
# Skill Name
## When to Use
Be specific about what triggers this skill.
## Implementation Pattern
Step-by-step procedures, examples, templates.
## Anti-Patterns (DO NOT DO)
What NOT to do, with examples.
## Related Documentation
Link to corresponding ADR for human context.
```
### Best Practices
✅ **Do**:
- Write clear descriptions that help Claude select the skill
- Provide concrete examples and templates
- Document anti-patterns explicitly
- Keep instructions under 5k tokens
- Link to corresponding ADR
❌ **Don't**:
- Duplicate WHY explanations (that's in ADRs)
- Write overly generic descriptions
- Include unnecessary context in metadata
- Exceed 5k tokens for instructions
## Skill Discovery
Claude Code automatically:
1. Scans `skills/*/SKILL.md` at session start
2. Loads metadata (100 tokens per skill)
3. Selects relevant skills based on task
4. Loads full instructions only for selected skills
5. Accesses resources on-demand via filesystem
**You don't need to manually invoke skills** - Claude does it automatically based on task recognition.
## Examples
See existing skills in this directory:
- `nix-http-server/SKILL.md`
- `revealjs-presentation/SKILL.md`
- `adr-documentation/SKILL.md`
## Resources
- Anthropic Skills Documentation: https://docs.claude.com/en/docs/agents-and-tools/agent-skills
- Skills Repository: https://github.com/anthropics/skills
- This project's ADRs: `docs/adr/`

View file

@ -0,0 +1,227 @@
---
name: adr-documentation
description: Create and maintain Architecture Decision Records (ADRs) for human documentation. Use when documenting architectural decisions, not for AI implementation guidance.
---
# ADR Documentation Skill
## Purpose
ADRs (Architecture Decision Records) are **human documentation** that explain WHY architectural decisions were made. They are NOT for AI implementation guidance - that's what skills are for.
## When to Use
- Documenting a significant architectural decision
- Explaining technology choices to team members
- Creating governance artifacts for reviews
- Preserving historical context for future maintainers
## When NOT to Use
❌ Don't create ADRs for AI to consume as implementation guidance
✅ Instead, create a **skill** that encodes the decision as executable instructions
## ADR Structure
```markdown
# ADR NNN: Title
## Status
[Proposed | Accepted | Deprecated | Superseded by ADR-XXX]
## Context
What is the issue/situation that motivates this decision?
- What problems are we trying to solve?
- What constraints exist?
- What is the current state?
## Decision
What did we decide to do?
Be specific and concrete. This should be implementable.
## Rationale
Why did we make this decision?
### Alternatives Considered
What other options did we evaluate and why were they rejected?
1. **Alternative A**
- Pros: ...
- Cons: ...
- Reason for rejection: ...
2. **Alternative B**
- Pros: ...
- Cons: ...
- Reason for rejection: ...
## Consequences
### Positive
- What benefits does this decision provide?
- What problems does it solve?
### Negative
- What are the downsides or trade-offs?
- What new problems might this create?
### Mitigations
- How can we address the negative consequences?
- What can we do to minimize downsides?
## Implementation Notes
(Optional) High-level guidance for implementation, but detailed procedures belong in skills, not ADRs.
## Related
- Links to related ADRs
- Links to corresponding skills
- External documentation
```
## ADR Numbering
Use sequential zero-padded numbers:
- `001-first-decision.md`
- `002-second-decision.md`
- `010-tenth-decision.md`
## ADR Lifecycle
1. **Proposed** - Under discussion, not yet accepted
2. **Accepted** - Decision is made and active
3. **Deprecated** - No longer recommended but not superseded
4. **Superseded** - Replaced by a newer ADR (reference it)
**Important**: Never delete ADRs. They preserve historical context.
## Directory Structure
```
docs/
└── adr/
├── README.md # Index and overview
├── 001-first.md
├── 002-second.md
└── 003-third.md
```
## Relationship to Skills
**The Modern Pattern**:
```
┌──────────────────────────────────────┐
│ Make Architectural Decision │
└────────────┬─────────────────────────┘
│
┌────────┴────────┐
▼ ▼
┌──────────┐ ┌─────────┐
│ ADR │ │ Skill │
│ (Human) │ │ (AI) │
└──────────┘ └─────────┘
│ │
▼ ▼
Explains WHY Implements HOW
For humans For AI
In docs/adr/ In skills/
```
### Example Integration
**ADR 002**: "Use Caddy for HTTP serving, not Python"
- Location: `docs/adr/002-nix-flake-architecture.md`
- Purpose: Explain WHY we chose Caddy
- Audience: Human developers
- Document: Rationale, alternatives, consequences
**Skill**: `nix-http-server`
- Location: `skills/nix-http-server/SKILL.md`
- Purpose: Automate Caddy server creation, enforce no-Python constraint
- Audience: Claude AI
- Contains: Step-by-step procedures, templates, validation scripts
## ADR Template
See `docs/adr/template.md` for a starter template (if it exists), or use the structure above.
## Best Practices
### Writing Effective ADRs
✅ **Do**:
- Focus on WHY, not HOW
- Document alternatives considered
- Be honest about trade-offs
- Use clear, simple language
- Include concrete examples
- Link to related decisions
❌ **Don't**:
- Document implementation details (use skills instead)
- Write ADRs that AI should consume
- Delete old ADRs (mark as Superseded instead)
- Make decisions in ADRs that should be skills
- Use jargon without explanation
### Context Window Efficiency
**Old pattern** (inefficient):
- ADR contains both WHY and detailed HOW
- AI must load entire ADR into context (500-2000 tokens)
- Doesn't scale beyond ~10-20 ADRs
**New pattern** (efficient):
- ADR contains only WHY (for humans)
- Skill contains HOW (for AI, ~100 tokens metadata)
- Scales to hundreds of patterns
## Validation
When creating or updating an ADR, ensure:
- [ ] Status is one of: Proposed, Accepted, Deprecated, Superseded
- [ ] All sections are present and filled out
- [ ] Alternatives are documented with pros/cons
- [ ] Consequences (positive AND negative) are listed
- [ ] Related ADRs/skills are linked
- [ ] Decision is specific and actionable
- [ ] Language is clear and accessible
## Examples
See existing ADRs in this repository:
- `docs/adr/001-presentation-technology.md` (→ corresponds to `revealjs-presentation` skill)
- `docs/adr/002-nix-flake-architecture.md` (→ corresponds to `nix-http-server` skill)
- `docs/adr/003-demo-implementation-strategy.md` (→ corresponds to this skill)
## Creating a Corresponding Skill
After creating an ADR, ask:
**"Should this have a corresponding skill?"**
If YES to any:
- Does this decision involve repetitive implementation patterns?
- Should AI automatically apply these standards?
- Can this be automated with scripts/templates?
- Do we want perfect consistency in implementation?
Then create a skill in `skills/<name>/SKILL.md` that:
- References the ADR for context
- Provides step-by-step implementation procedures
- Includes templates and examples
- Enforces the constraints from the ADR
## Related Documentation
- `docs/adr/README.md` - Index of all ADRs
- `skills/` - Corresponding AI implementation skills

View file

@ -0,0 +1,163 @@
---
name: nix-http-server
description: Create HTTP servers for Nix flake projects. Use when serving static files or running development servers. CRITICAL CONSTRAINT - Never suggest Python dependencies.
---
# Nix HTTP Server Skill
## Core Constraint
**NEVER suggest Python-based HTTP servers** (python -m http.server, etc.)
All dependencies MUST come from nixpkgs only.
## When to Use
- User needs to serve static files from a Nix project
- User wants to create development servers
- User needs process orchestration for multiple services
- Project has a flake.nix file
## Implementation Pattern
### 1. Use Caddy for HTTP Serving
Caddy is the approved HTTP server because:
- Available in nixpkgs
- Supports configuration as code
- Better features than simple Python server
- Works with process-compose orchestration
### 2. Configuration Generation
Generate configurations at build time using Nix expressions:
```nix
makeCaddyConfig = pkgs: port: root: pkgs.writeText "Caddyfile" ''
:${toString port} {
root * ${root}
file_server browse
encode gzip
log {
output stdout
format console
}
}
'';
```
OR generate at runtime for development flexibility:
```bash
# Generate Caddyfile at runtime
CADDY_CONFIG=$(mktemp)
cat > "$CADDY_CONFIG" <<EOF
:8000 {
root * $PWD/presentation
file_server browse
encode gzip
}
EOF
caddy run --config "$CADDY_CONFIG" --adapter caddyfile
```
### 3. Process Orchestration
For multiple services, use process-compose:
```nix
makeProcessComposeConfig = pkgs: processes: pkgs.writeText "process-compose.yaml" (
builtins.toJSON {
version = "0.5";
inherit processes;
}
);
```
### 4. Flake App Pattern
Create apps in flake.nix that:
- Check for required directories in $PWD
- Generate configs at runtime (for dev flexibility)
- Use --tui=false for process-compose (avoids /dev/tty errors)
- Add --adapter caddyfile flag when using Caddyfile format
## Example Implementation
See `/Users/sscoble/Projects/beyond-the-prompt/flake.nix` for working examples:
- `nix run .#present` - Single server
- `nix run .#demo` - Multiple servers with process-compose
## Key Technical Details
### Caddy Flags
- `--config <path>` - Path to config file
- `--adapter caddyfile` - Parse as Caddyfile format (not JSON)
- `run` - Run server (blocking)
### Process-Compose Flags
- `--tui=false` - Disable TUI (required for non-interactive environments)
- `-f <config>` - Config file path
### Runtime Config Pattern
```bash
#!/usr/bin/env bash
set -euo pipefail
# Validate directory exists
CONTENT_ROOT="$PWD/presentation"
if [ ! -d "$CONTENT_ROOT" ]; then
echo "Error: presentation/ directory not found"
exit 1
fi
# Generate config at runtime (allows serving from working directory)
CADDY_CONFIG=$(mktemp)
trap "rm -f $CADDY_CONFIG" EXIT
cat > "$CADDY_CONFIG" <<EOF
:8000 {
root * $CONTENT_ROOT
file_server browse
encode gzip
}
EOF
# Run server
caddy run --config "$CADDY_CONFIG" --adapter caddyfile
```
## Anti-Patterns (DO NOT DO)
❌ **Never** suggest `python -m http.server`
❌ **Never** suggest `python3 -m http.server`
❌ **Never** add Python to buildInputs/devShell for HTTP serving
❌ **Never** suggest `npx http-server` (requires Node.js, use nixpkgs)
❌ **Never** hardcode absolute paths in Nix expressions (breaks portability)
## Multi-Platform Support
Always use `forAllSystems` pattern for cross-platform compatibility:
```nix
supportedSystems = [
"x86_64-linux"
"aarch64-linux"
"x86_64-darwin"
"aarch64-darwin"
];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems
(system: f system (import nixpkgs { inherit system; }));
```
## Related Documentation
Human-readable architectural rationale in: `docs/adr/002-nix-flake-architecture.md`
## Templates
See `templates/` directory for:
- Caddyfile examples
- process-compose.yaml examples
- Flake app script templates

View file

@ -0,0 +1,91 @@
---
name: remark-presentation
description: Create Remark.js markdown-based presentations for technical talks. Use when building slide decks from markdown files. Optimized for large screens and code-heavy content.
---
# Remark.js Presentation Skill
## When to Use
- User needs to create a presentation or slide deck
- User wants markdown-based presentations (easy to version control)
- User needs technical presentations with lots of code
- User wants simple, minimal presentation framework
## Technology Choice
**Use Remark.js** (markdown-driven slideshow) because:
- Pure markdown content - extremely simple
- No build process - just HTML + markdown file
- Excellent code highlighting
- Works perfectly with version control
- Very lightweight
## Basic Structure
**index.html**:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Presentation Title</title>
<link rel="stylesheet" href="assets/theme.css">
</head>
<body>
<script src="https://remarkjs.com/downloads/remark-latest.min.js"></script>
<script>
var slideshow = remark.create({
sourceUrl: 'slides.md',
highlightStyle: 'monokai',
highlightLines: true,
ratio: '16:9'
});
</script>
</body>
</html>
```
**slides.md**:
```markdown
class: center, middle
# Presentation Title
Subtitle
---
# Slide Title
Content
- Point 1
- Point 2
---
# Code
\`\`\`nix
{ apps.present = ...; }
\`\`\`
```
## Slide Separators
- `---` creates new slide
- `--` creates incremental reveal
- `???` adds presenter notes
## Large Screen Optimization (100" at 15ft)
```css
body { font-size: 38px; }
h1 { font-size: 3em; }
h2 { font-size: 2.5em; }
```
## Related Documentation
See: `docs/adr/001-presentation-technology.md`