Implement ADR 0010 with a phased, low-regret rollout:
- Tools can declare dependencies in
GeneratedProgram. - Runtime can validate, normalize, and log dependency manifests.
- Runtime can materialize Ruby gem environments with deterministic identity.
- Runtime can eventually execute in isolated workers with JSON-only IPC boundaries.
In scope:
- Provider output contract evolution (
code->GeneratedProgram). - Dependency manifest normalization and compatibility checks (monotonic growth).
- Runtime source/policy configuration (
gem_sources,allowed_gems,blocked_gems). - Phase-gated runtime execution architecture (in-process activation, then worker isolation).
- Typed error taxonomy and observability updates.
Out of scope:
- Security hardening beyond documented policy controls.
- Lua runtime implementation (Ruby-only delivery first).
- Prompt-quality optimization beyond schema/policy compliance nudges.
- Preserve Tool Builder/Tool ubiquitous language and intent-first API.
- Keep
Agent.for(...)synchronous. - Remove backward-compatibility shims and migrate to
GeneratedProgramas the only provider output shape. - Introduce async preparation only when worker isolation exists (Phase 3).
- Phase 1 deliverables:
- Phase 2 deliverables:
- Phase 3 deliverables:
- Capture and validate dependency declarations.
- Prove schema reliability and prompt adherence.
- Add no execution model change for stdlib-only flows.
- Provider API evolution:
- Rename
generate_code(...)togenerate_program(...)in provider adapters. - Return structured payload only (
{code, dependencies}).
- Rename
- Tool schema update:
- Add optional
dependencies[]to runtime helper schema.
- Add optional
- Introduce
GeneratedProgrammodel:- parse/validate payload shape.
- expose
codeand normalized dependencies.
- Introduce
DependencyManifest:- normalize gem names/versions.
- detect duplicate/conflicting constraints.
- Logging update:
- record
program_dependenciesandnormalized_dependencies.
- record
- Error update:
- add
invalid_dependency_manifest.
- add
- Provider adapter tests:
- structured payload parse.
- Manifest tests:
- normalization and conflict detection.
- Runtime tests:
- invalid manifest maps to
Outcome.errorwitherror_type=invalid_dependency_manifest.
- invalid manifest maps to
- Acceptance tests:
- stdlib flows still pass unchanged.
- No behavior regressions in existing acceptance suite.
-
95% generated payloads in smoke runs include valid manifest structures (or empty dependencies).
- New log fields emitted for every dynamic call.
- Materialize deterministic gem environments by
env_id. - Enforce runtime source/policy controls.
- Enforce monotonic manifest growth semantics in execution flow.
EnvironmentManager:- compute
env_idfrom engine/version/patch/platform/manifest. - create env dir under
$XDG_CACHE_HOME/recurgent/ruby-envs/<env_id>/. - generate Gemfile using runtime
gem_sources. - run
bundle lock,bundle install. - write
.readymetadata and checksum.
- compute
- Monotonic manifest growth:
- persist tool
env_manifest. - allow additive-only growth.
- reject incompatible mutation with
dependency_manifest_incompatible.
- persist tool
- Runtime policy enforcement:
- add runtime config fields:
gem_sourcessource_modeallowed_gemsblocked_gems
- enforce
dependency_policy_violationbefore resolve/install.
- add runtime config fields:
- Observability:
- add
env_id,environment_cache_hit,env_prepare_ms,env_resolve_ms,env_install_ms.
- add
- Environment manager tests:
- deterministic
env_idincludingRUBY_PLATFORM. - cache hit path skips install.
- lock/install failure mapping.
- deterministic
- Policy tests:
- allowlist accept/reject.
- blocklist reject.
- source mode behavior (
public_only,internal_only).
- Integration tests:
- install once, reuse on second call.
- additive manifest growth triggers new
env_id. - incompatible mutation (
nokogiri ~> 1.0->nokogiri ~> 2.0) returnsdependency_manifest_incompatible.
- Materialization errors are consistently typed (
dependency_resolution_failed,dependency_install_failed,dependency_activation_failed,dependency_policy_violation). - Warm-path calls avoid install step.
- Monotonic growth contract verified:
- additive changes create a new
env_id. - incompatible mutations return
dependency_manifest_incompatible.
- additive changes create a new
- Remove gem-activation pollution by isolating tool execution.
- Enforce JSON-only cross-process boundary.
- Add worker lifecycle reliability guarantees.
- Introduce async preparation semantics with
Agent.prepare(...).
WorkerExecutor:- worker boot in env with
bundler/setup. - newline-delimited JSON request/response protocol (
ipc_version).
- worker boot in env with
WorkerSupervisor:- worker pool/registry keyed by tool/env.
- per-call timeout and idle timeout.
- restart policy and max restart count.
- cleanup on shutdown (TERM -> KILL escalation, child reaping).
- JSON boundary enforcement:
- serialize args/kwargs/result/context.
- map non-serializable values to
non_serializable_result.
- Context migration on env growth:
- restart worker on
env_idchange. - restore serializable context snapshot.
- restart worker on
- Async preparation API:
- add
Agent.prepare(...) -> PreparationTicket. - implement
status,await,agent,on_ready,on_error. - emit
environment_preparingfor calls before readiness.
- add
- Worker executor tests:
- request/response protocol correctness.
- non-serializable mapping.
- Supervisor tests:
- restart behavior.
- timeout enforcement.
- max-worker cap.
- shutdown cleanup.
- End-to-end tests:
- tool survives multiple calls with preserved context.
- env growth triggers worker restart and continued execution.
- Preparation ticket tests:
- lifecycle transitions.
- callback execution.
- timeout behavior in
await.
- No zombie workers after full test suite.
- Crash/timeout paths emit typed retriable outcomes (
worker_crash,timeout). - JSON boundary is enforced for every worker call.
Agent.preparesemantics verified with asynchronous readiness andenvironment_preparingoutcomes.
- System prompt additions:
- define
GeneratedProgramoutput shape. - require
dependenciesentries for all non-stdlibrequireusage. - require minimal manifests (declare only actually needed gems).
- instruct no speculative dependency additions.
- define
- User prompt additions:
- include concrete example payload:
- stdlib-only method:
dependencies: [] - gem-backed method:
dependencies: [{name, version}].
- stdlib-only method:
- include reminder that dependency declarations are part of the execution contract.
- include concrete example payload:
- Retry prompt additions:
- if manifest parse fails, include structured corrective feedback (invalid field, conflict, forbidden gem).
- if policy check fails, require alternative implementation using allowed dependencies or stdlib.
- if dependency activation fails, prompt tool to narrow/change dependency set.
- Prompt verification:
- add deterministic prompt unit checks that required contract language appears in system/user/retry prompts.
- Update
specs/contract/v1/agent-contract.mdafter Phase 1 completion. - Add contract scenarios for dependency errors and environment-preparing flow.
- Keep ADR 0010 as
proposeduntil Phase 1 lands; promote status toacceptedafter Phase 2 stability.
- Default policy stays open for ergonomics:
- source:
https://rubygems.org - allowlist: none
- blocklist: none
- source:
- Enterprise deployment can override via runtime config.
- Land Phase 1 as the default path (no legacy fallback path retained).
- Land Phase 2 as the default execution path for dependency materialization.
- Land Phase 3 as the default execution path for worker isolation.
- Validate each phase with its exit criteria before beginning the next phase.
- Risk: dependency declaration quality from LLM is noisy.
- Mitigation: strict validation + retry hints + logging feedback loop.
- Risk: first-call latency hurts interactive sessions.
- Mitigation:
Agent.prepare, env caching, optional prewarm.
- Mitigation:
- Risk: worker lifecycle bugs degrade reliability.
- Mitigation: explicit supervision tests before defaulting to worker mode.
- Phase 1 merged with tests and docs.
- Phase 2 merged with policy enforcement and monotonic environment behavior.
- Phase 3 merged with supervisor, JSON boundary, and
Agent.prepare. - Contract docs updated at each phase gate.
- Observability dashboards/watch tooling can display new environment fields.