5.8 KiB
Epic 8 — Tool System (core:tools)
completed deliverables
1. shared vocabulary in core:events
introduced tool identity, request/receipt types, and a serialization bridge for dynamic parameters.
final structures:
ToolInvocationId— typealias added toIdentityTypes.ktToolRequest— captures invocation identity, session, stage, tool name, and arbitrary parametersToolReceipt— captures exit code, output summary, structured output, affected entities, duration, tier, and timestampAnyMapSerializer—Map<String, Any>↔ JSON bridge viaJsonElement; required because kotlinx.serialization cannot serializeAnydirectly
key properties:
- shared vocabulary lives in
core:eventsto prevent circular dependencies core:toolsdepends oncore:events, not the reverse- parameters and structured output are fully round-trip serializable
2. tool lifecycle events in core:events
introduced five event classes covering the full execution lifecycle of a tool invocation.
final events:
ToolInvocationRequestedEvent— invocation submitted with request and tierToolExecutionStartedEvent— execution begunToolExecutionCompletedEvent— execution succeeded; carriesToolReceiptToolExecutionFailedEvent— execution failed; carries reason stringToolExecutionRejectedEvent— invocation rejected before execution; carries tier and reason
all five events:
- implement
EventPayload - registered in
Serialization.ktpolymorphic block - validated via 8 round-trip serialization tests
3. tool contract interface (core:tools)
defined the Tool interface as the stable contract that all tool implementations must satisfy.
final structures:
Tool— plain interface (not sealed; infrastructure implements it)ToolCapability— enum:FILE_READ,FILE_WRITE,NETWORK_ACCESS,SHELL_EXEC,PROCESS_SPAWNValidationResult— sealed interface:Valid/Invalid(reason)
interface properties:
name: Stringtier: TierrequiredCapabilities: Set<ToolCapability>validateRequest(request: ToolRequest): ValidationResult
core:tools declares the contract; it never executes tools. Infrastructure modules provide concrete implementations.
4. event-sourced state model
introduced the state layer that tracks all tool invocations for a session.
final structures:
ToolInvocationStatus— enum:REQUESTED,STARTED,COMPLETED,FAILED,REJECTEDToolInvocationRecord— holds the full lifecycle of one invocation: id, name, tier, request, status, optional receipt, requested/completed timestampsToolState— root state:invocations: List<ToolInvocationRecord>
properties:
- fully
@Serializablethroughout - state is always rebuilt from events; never persisted independently
receiptandcompletedAtare nullable; populated only on terminal events
5. reducer, projector, and repository
implemented the standard CORREX pattern for event-sourced state reconstruction.
final components:
ToolReducer (interface)
└── DefaultToolReducer (applies 5 lifecycle events to ToolState)
ToolProjector (implements Projection<ToolState>)
└── bridges reducer to EventReplayer infrastructure
DefaultToolRepository
└── thin wrapper over EventReplayer<ToolState>
└── getToolState(sessionId): ToolState
reducer behavior:
ToolInvocationRequestedEvent→ appends newREQUESTEDrecordToolExecutionStartedEvent→ transitions matching record toSTARTEDToolExecutionCompletedEvent→ transitions toCOMPLETED, attaches receipt and completedAtToolExecutionFailedEvent→ transitions toFAILED, sets completedAtToolExecutionRejectedEvent→ transitions toREJECTED, sets completedAt- unrelated events → pass through unchanged
wiring (DefaultEventReplayer(store, ToolProjector(DefaultToolReducer()))) is left to infrastructure modules.
6. mock tools in testing:fixtures
introduced three deterministic tool implementations for use across test suites.
final tools:
EchoTool— tier T0, always returnsValidationResult.ValidFailingTool— tier T2, always returnsValidationResult.Invalid("simulated validation failure")RejectedTool— tier T4, always returnsValidationResult.Valid
testing/fixtures/build.gradle gains :core:tools dependency.
tier assignment mirrors the approval tier model: T0 (auto-approve), T2 (requires approval), T4 (always reject).
final architecture after Epic 8
Tool (interface — core:tools)
↓
ToolRequest / ToolReceipt (core:events — shared vocabulary)
↓
5 lifecycle EventPayload subclasses (core:events)
↓
DefaultToolReducer → ToolState (event-sourced projection)
↓
ToolProjector → EventReplayer → DefaultToolRepository
major architectural outcomes
Epic 8 established:
- safe tool contract: execution is infrastructure's responsibility, not core's
- full lifecycle event coverage from request to terminal state
- deterministic, replay-safe tool invocation tracking
- tier-aware tool classification aligned with the approval system
- reusable mock tools for integration and deterministic test suites
what Epic 8 intentionally does NOT include
not implemented:
- concrete tool implementations (file I/O, shell, network — infrastructure concern)
- approval gating logic (Epic 5)
- tool registry or discovery mechanism
- execution engine or sandbox enforcement
- kernel orchestration of tool invocations
those are explicitly deferred to infrastructure modules and later epics.
final state
Correx now has:
a complete tool abstraction layer: a stable contract interface, a full five-event lifecycle model, event-sourced invocation state with reducer/projector/repository, and deterministic mock tools for testing — with no coupling to execution infrastructure.