A self-evolving coding agent built with the Claude Agent SDK. Bloom autonomously reads its own source code, identifies improvements, implements them, and commits passing changes.
Inspired by yoyo-evolve.
Bloom is a proof-of-concept demonstrating that an AI agent can safely and transparently evolve its own source code. Every change must pass the build and test suite before it is committed, every decision is logged in a public journal, and an immutable constitution (IDENTITY.md) defines hard boundaries that the agent cannot override. The project is guided by community input — anyone can open an issue to suggest what Bloom should improve next.
- Developers interested in autonomous code agents and self-improving systems
- Researchers studying safe AI self-modification and transparent decision-making
- Open-source contributors who want to guide an evolving agent via issues and feedback
Bloom measures its own progress through quantitative metrics (available via pnpm stats):
| Metric | What it measures |
|---|---|
| Build pass rate | % of cycles where the build passes after evolution — the core safety metric |
| Improvement throughput | Average improvements successfully committed per cycle |
| Test coverage trend | Whether test counts grow over time (a proxy for code quality) |
| Cost efficiency | Average cost per cycle — lower is better for sustainability |
| Community responsiveness | How quickly community issues are triaged and addressed |
Bloom is an ongoing experiment, not a product with a finish line. However, the project will have demonstrated its thesis when:
- It has sustained a >90% build pass rate over 50+ cycles
- It has autonomously added meaningful capabilities beyond its initial feature set
- Community-filed issues are routinely triaged, prioritized, and resolved by the agent
- The evolution history serves as a public reference for safe autonomous code modification
Every 4 hours, Bloom runs an evolution cycle via GitHub Actions:
- Pre-flight - Verifies build and tests pass before starting
- Memory & Planning - Loads accumulated learnings, strategic context, and the project roadmap
- Assessment - Reads its own code, community issues, memory, and roadmap to identify improvements
- Evolution - Implements 1-3 improvements, testing each before committing
- Build verification - Verifies build still passes after evolution; reverts if broken
- Learning extraction - Stores categorized learnings and updates strategic context
- Roadmap update - Updates ROADMAP.md with cycle results
- Push - Pushes passing changes to main
The workflow retries up to 3 times with backoff on failure.
Bloom accumulates knowledge across evolution cycles via two mechanisms:
- Structured learnings — Categorized insights (pattern, anti-pattern, domain, tool-usage, process) stored in SQLite with relevance decay. Newer learnings naturally rank higher than older ones. Injected into each assessment prompt so Bloom builds on past experience.
- Strategic context — A persistent narrative summary of focus areas, trajectory, and ongoing goals. Updated each cycle so Bloom maintains awareness of its multi-cycle direction.
Bloom manages its own kanban-style roadmap using a local ROADMAP.md file:
- Hybrid planning — Bloom proposes its own improvement goals and incorporates community issues, with reactions influencing priority
- Automated status tracking — Items flow from Backlog → Up Next → In Progress → Done as Bloom works through cycles
- Priority algorithm — "In Progress" items are resumed first (unfinished work), then "Up Next" (sorted by reactions), then "Backlog"
- Completion notes — When items move to Done, a summary of what was accomplished is recorded automatically
All state is stored in bloom.db (SQLite with WAL mode):
| Table | Purpose |
|---|---|
cycles |
One row per evolution cycle with outcome metrics (passed count, total count, precise duration_ms) |
journal_entries |
Structured journal data (attempted, succeeded, failed, learnings, strategic_context) |
phase_usage |
Token counts (input/output), costs, and duration per phase — aggregated into cycle stats |
issue_actions |
Tracks which issues were acknowledged or closed |
learnings |
Categorized knowledge with relevance scores |
strategic_context |
High-level narrative summaries per cycle |
- Immutable constitution (
IDENTITY.md) - Defines purpose and boundaries, protected by hooks - Runtime type validation - All external data (SQLite rows, SDK messages, GitHub API responses, hook inputs) is validated with runtime type guards — zero unsafe
ascasts on external data - Test-gated commits - Only changes that pass
pnpm build && pnpm testare committed - Post-evolution verification - Build is verified after the agent runs; broken builds are reverted
- Journal protection - Journal entries are stored in SQLite;
JOURNAL.mdis protected from overwrites by safety hooks - Dangerous command blocking - Safety hooks prevent
rm -rf, force pushes, etc. - Budget limits - Max 50 turns and $5 per evolution cycle
- Best-effort externals - GitHub API failures (issues, projects) never block evolution
The full evolution journal is published at the repo's GitHub Pages site.
Open an issue with the agent-input label to suggest improvements. Issues are prioritized by reaction count. Bloom triages issues each cycle and can auto-close resolved ones.
src/
├── index.ts # Main entry point — orchestrates the evolution cycle
├── agent-phases.ts # Assessment & evolution phase runners with dependency injection for testability
├── context.ts # Evolution context loader — gathers identity, journal, issues, memory, and planning state
├── phases.ts # Exported phase helpers (build verification, planning status, push) — extracted for testability
├── orchestrator.ts # Evolution result processing (journal, learnings, strategic context) and cycle summary
├── evolve.ts # Assessment & evolution prompt building
├── errors.ts # Safe error extraction: errorMessage() for thrown values, execSyncOutput() for subprocess failures
├── memory.ts # Learning extraction, storage, and prompt formatting
├── planning.ts # Local ROADMAP.md parsing and item CRUD via withRoadmapItems helper (collision-safe IDs, duplicate prevention)
├── db.ts # SQLite persistence (bloom.db) with runtime row validation
├── assess.ts # Standalone read-only assessment CLI — runs assessment phase without modifying state (pnpm assess)
├── journal.ts # CLI entry point for exporting journal entries (JSON/Markdown)
├── stats.ts # CLI entry point for querying evolution statistics
├── roadmap.ts # CLI entry point for viewing the current roadmap grouped by status (pnpm roadmap)
├── triage.ts # Issue triage and lifecycle management (injectable QueryFn for testability)
├── issues.ts # GitHub issues integration
├── github-app.ts # GitHub App JWT auth + REST API client
├── safety.ts # Pre-tool-use hooks & dangerous command blocking
├── lifecycle.ts # Git operations, build verification, safety tags
├── outcomes.ts # Cycle metrics tracking (passed + total test counts, precise duration)
├── page-helpers.ts # Pure HTML generation helpers for the GitHub Pages site (roadmap, journal, stats pages)
└── usage.ts # Token/cost/cache usage tracking — accepts unknown inputs with runtime guards
Evolution runs automatically on a 4-hour cron schedule. You can also trigger it manually from the Actions tab → Bloom Evolution → Run workflow.
| Secret | Description |
|---|---|
ANTHROPIC_API_KEY |
Anthropic API key for Claude |
BLOOM_APP_PRIVATE_KEY |
GitHub App private key (PEM) for issue management and project board |
GITHUB_TOKEN is provided automatically by GitHub Actions.
The GitHub App (used for issue and project management) needs:
- Issues: Read and write
- Projects: Read and write
pnpm install
pnpm build
pnpm testANTHROPIC_API_KEY=sk-... pnpm run evolvepnpm stats # Summary stats (success rate, costs, trends)
pnpm stats -- --last 10 # Stats for the last 10 cycles only
pnpm stats -- --since 700 # Stats starting from cycle 700 (inclusive)
pnpm stats -- --table # Per-cycle ASCII table
pnpm stats -- --table --verbose # Table with failure category column
pnpm stats -- --json # Machine-readable JSON (for scripting/CI)
pnpm stats -- --help # Print all available flagsPrints cycle statistics (success rate, test trends, costs, token usage) and the latest strategic context. Useful for answering "how is Bloom doing?" without running a full evolution cycle.
pnpm journal # JSON output (default)
pnpm journal -- --md # Markdown output
pnpm journal -- --limit 5 # Limit to last 5 entriesExports journal entries to stdout. The JSON format is designed for use by the GitHub Pages site, while Markdown is useful for human reading.
pnpm roadmap
pnpm roadmap --filter "in progress" # show only In Progress items
pnpm roadmap --filter backlog # show only Backlog items
pnpm roadmap --json # machine-readable JSON output
pnpm roadmap --json --filter done # JSON output filtered to Done itemsPrints the current ROADMAP.md as a formatted summary, grouped by status (In Progress → Up Next → Backlog → Done) with visual markers, linked issue numbers, and body previews. Useful for checking Bloom's current focus without reading raw Markdown.
The --filter <status> flag restricts output to a single status column (case-insensitive). Valid values: backlog, up next, in progress, done. The --json flag emits machine-readable JSON including a summary with total and per-status item counts.
