Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
3a09236
docs: gentle deadline example (matz round 16)
claude Jul 7, 2026
be7ce65
docs: railway plan example (solnic round 16)
claude Jul 7, 2026
38b4f2c
docs: schedule equivalence prover example (eregon round 16)
claude Jul 7, 2026
fdd245c
docs: configurable cops example (bbatsov round 16)
claude Jul 7, 2026
d004fc0
docs: spend ledger example (noelrap round 16)
claude Jul 7, 2026
2495ccb
docs: shadow traffic example (eileencodes round 16)
claude Jul 7, 2026
f5cfc3c
docs: discovery testing example (searls round 16)
claude Jul 7, 2026
2a726b1
docs: progress channel example (palkan round 16)
claude Jul 7, 2026
8e63ca9
docs: kill switch example (jnunemaker round 16)
claude Jul 8, 2026
5649a3c
docs: release rehearsal example (hsbt round 16)
claude Jul 8, 2026
f184add
fix: force UTF-8 on git log output in two examples
claude Jul 8, 2026
fd74f9d
docs: round 16 index and findings (the lottery round)
claude Jul 8, 2026
7e8149e
docs: plan heckler example (zenspider round 17)
claude Jul 8, 2026
e5b4523
docs: omakase scaffold example (dhh round 17)
claude Jul 8, 2026
01ca92a
docs: document refinery example (flavorjones round 17)
claude Jul 8, 2026
92502d9
docs: assembly doctor example (schneems round 17)
claude Jul 8, 2026
5e02257
docs: queue-time autoscaler example (nateberkopec round 17)
claude Jul 8, 2026
4f014b3
docs: capability autoloader example (fxn round 17)
claude Jul 8, 2026
31564ba
docs: supervision tree example (josevalim round 17)
claude Jul 8, 2026
f7d17bc
docs: support escalation example (obie round 17)
claude Jul 8, 2026
b566bb4
docs: plan lockfile example (indirect round 17)
claude Jul 8, 2026
23acabb
docs: shameless green example (sandimetz round 17)
claude Jul 8, 2026
3ee8701
docs: round 17 index and findings (the builders' round)
claude Jul 8, 2026
baae756
refactor: move example catalog and perspectives to codenamev/agentic-…
claude Jul 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -765,10 +765,18 @@ planner = Agentic::TaskPlanner.new("Write a blog post", config)
client = Agentic::LlmClient.new(config)
```

## Examples

A small set of canonical, offline-runnable examples lives in [`examples/`](examples/README.md) — start with `bundle exec ruby examples/ticket_screener.rb`.

The full catalog — 144 example programs covering the entire framework surface, plus the persona-driven field notes that shaped it — lives in [codenamev/agentic-examples](https://github.com/codenamev/agentic-examples), with refs marking which Agentic version each snapshot is certified against (`agentic-v0.2.0` matches this release).

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

Two repo referees live in `bin/`: `bundle exec ruby bin/doctest.rb` verifies every code example in the docs runs (or is deliberately annotated as illustrative), and `bundle exec ruby bin/release_rehearsal.rb` builds, audits, cleanly installs, and boots the packaged gem before you tag anything.

### Running Tests

Agentic includes a comprehensive test suite with both unit tests and integration tests. To run all tests:
Expand Down
2 changes: 1 addition & 1 deletion examples/doctest_runner.rb → bin/doctest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# "<!-- doctest: illustrative (reason) -->" before a README fence.
# Unannotated failure = exit 1. Docs rot at the speed of a red build.
#
# bundle exec ruby examples/doctest_runner.rb
# bundle exec ruby bin/doctest.rb
#
# Runs offline; each snippet gets its own process and tmpdir.

Expand Down
99 changes: 99 additions & 0 deletions bin/release_rehearsal.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# frozen_string_literal: true

# The Release Rehearsal: your repo is not your gem. The gem is
# whatever the gemspec PACKAGES, installed into a clean GEM_HOME,
# required by a Ruby that has never seen your working directory -
# and the day to discover a file missing from the package is today,
# on this machine, not release day in someone's CI. Build, audit,
# install, boot: the full ceremony, rehearsed.
#
# bundle exec ruby bin/release_rehearsal.rb
#
# Runs offline; exits 1 if the packaged gem can't do its job.

require_relative "../lib/agentic"
require "open3"
require "rbconfig"
require "tmpdir"

failures = []
stage = Dir.mktmpdir("agentic_rehearsal")

# --- act 1: build the actual artifact --------------------------------------------
out, err, status = Open3.capture3("gem", "build", "agentic.gemspec", "--output", File.join(stage, "rehearsal.gem"))
if status.success?
puts " act 1 - gem build: ok (#{File.size(File.join(stage, "rehearsal.gem")) / 1024}KB)"
else
failures << "build failed"
puts " act 1 - gem build FAILED: #{err.lines.last&.strip || out.lines.last&.strip}"
end

# --- act 2: audit the manifest - every lib file must be aboard -------------------
spec = Gem::Specification.load("agentic.gemspec")
packaged = spec.files
missing = Dir["lib/**/*.rb"].reject { |f| packaged.include?(f) }
version_ok = spec.version.to_s == Agentic::VERSION
failures << "manifest missing #{missing.size} lib file(s)" if missing.any?
failures << "version drift" unless version_ok
puts " act 2 - manifest audit: #{packaged.size} files packaged; lib coverage #{missing.empty? ? "complete" : "MISSING #{missing.take(3).join(", ")}"}"
puts " version: gemspec #{spec.version} == Agentic::VERSION #{Agentic::VERSION} - #{version_ok ? "agree" : "DRIFT"}"

# --- act 3: install into a clean GEM_HOME ----------------------------------------
gem_home = File.join(stage, "gem_home")
_, err, status = Open3.capture3(
{"GEM_HOME" => gem_home},
"gem", "install", "--local", "--no-document", "--ignore-dependencies",
File.join(stage, "rehearsal.gem")
)
if status.success?
puts " act 3 - clean install: ok (GEM_HOME=#{File.basename(gem_home)})"
else
failures << "install failed"
puts " act 3 - install FAILED: #{err.lines.last&.strip}"
end

# --- act 4: boot the INSTALLED gem, far from this repo ---------------------------
# The child's load path knows the temp GEM_HOME (for our gem) and the
# host gem path (for dependencies) - and pointedly NOT this repo's lib/
probe = <<~RUBY
gem "agentic"
require "agentic"
raise "loaded from the repo, not the package!" if Agentic.method(:run).source_location.first.include?("/lib/agentic") && !Agentic.method(:run).source_location.first.include?("gem_home")
orchestrator = Agentic::PlanOrchestrator.new
task = Agentic::Task.new(description: "boot", agent_spec: {"name" => "b", "instructions" => "w"})
orchestrator.add_task(task, agent: ->(_t) { "the package works" })
print orchestrator.execute_plan.task_result(task.id).output
RUBY
# Scrub the inherited environment: under `bundle exec`, RUBYOPT
# smuggles bundler/setup into every child, which would quietly put
# THIS REPO back on the load path - the exact contamination the
# rehearsal exists to prevent (and its first run caught)
clean_env = {
"GEM_HOME" => gem_home,
"GEM_PATH" => "#{gem_home}#{File::PATH_SEPARATOR}#{Gem.paths.home}",
"RUBYOPT" => nil, "RUBYLIB" => nil,
"BUNDLE_GEMFILE" => nil, "BUNDLE_BIN_PATH" => nil, "BUNDLER_SETUP" => nil
}
out, err, status = Open3.capture3(clean_env, RbConfig.ruby, "-e", probe, chdir: stage)
if status.success? && out.include?("the package works")
puts " act 4 - boot from the package: \"#{out}\" (repo lib/ never on the path)"
else
failures << "packaged gem failed to boot"
puts " act 4 - boot FAILED: #{err.lines.grep_v(/warning/).last&.strip}"
end

puts
if failures.empty?
puts " the rehearsal passed all four acts, which certifies the thing"
puts " releases actually ship: not your repo, THE PACKAGE. the classic"
puts " release-day wounds are all rehearsable - a file added without"
puts " `git add` (invisible to git-ls-files manifests), a version.rb"
puts " bumped but gemspec pinned, an implicit load-order dependency"
puts " that only your spec_helper satisfied. rubygems maintenance is"
puts " mostly this lesson at scale: every gem that breaks on install"
puts " worked perfectly in its own repo. rehearse the ceremony in CI"
puts " and release day becomes a tag, not an event."
else
puts " REHEARSAL FAILED: #{failures.join("; ")} - fix before tagging."
end
exit(failures.empty? ? 0 : 1)
Loading
Loading