5 releases (2 stable)
Uses new Rust 2024
| 3.0.0 | Mar 3, 2026 |
|---|---|
| 1.0.0 | Feb 9, 2026 |
| 0.9.91 | Feb 9, 2026 |
| 0.9.9 | Feb 9, 2026 |
| 0.1.0 | Feb 7, 2026 |
#503 in Asynchronous
Used in 2 crates
485KB
11K
SLoC
Agent Harness API
fharness is the top-level orchestration layer for long-running agent workflows in Fiddlesticks.
It currently supports:
- initializer flow
- task agent incremental loop
- runtime wiring + run-level policy
- reliability + guardrails for production usage
fharness composes lower layers (fmemory, fchat, ftooling, fprovider) into a structured multi-run harness.
Responsibilities
- Run initializer setup for a session (manifest + feature list + progress + checkpoint)
- Run incremental task iterations one feature at a time
- Enforce clean handoff by recording explicit run outcomes
- Coordinate health checks, execution, validation, and persistence updates
fharness does not:
- Implement provider transports (
fprovider) - Implement turn orchestration internals (
fchat) - Implement tool runtimes (
ftooling) - Implement persistence internals (
fmemory)
Add dependency
[dependencies]
fharness = { path = "../fharness" }
fmemory = { path = "../fmemory" }
fchat = { path = "../fchat" }
Core types
Harness: orchestrator for initializer and task iterationsHarnessBuilder: runtime wiring for provider/chat/tooling/memoryInitializerRequest/InitializerResultTaskIterationRequest/TaskIterationResultRuntimeRunRequest/RuntimeRunOutcomeHealthChecker(NoopHealthCheckerdefault)OutcomeValidator(AcceptAllValidatordefault)FeatureSelector(FirstPendingFeatureSelectordefault)HarnessError/HarnessErrorKind
Initializer flow
run_initializer(...):
- Validates objective and feature list rules
- Builds/versions
SessionManifest - Uses
initialize_session_if_missing(...)for idempotent initialization - Persists initial progress + run checkpoint
If no feature list is provided, Harness generates a starter skeleton via starter_feature_list(...).
use std::sync::Arc;
use fharness::{Harness, InitializerRequest};
use fmemory::{InMemoryMemoryBackend, MemoryBackend};
let memory: Arc<dyn MemoryBackend> = Arc::new(InMemoryMemoryBackend::new());
let harness = Harness::new(memory);
let request = InitializerRequest::new("session-1", "run-init-1", "Build incremental harness");
let _result = harness.run_initializer(request).await?;
Task-Iteration incremental loop
run_task_iteration(...) executes one bounded run:
- Get bearings
- loads manifest/progress/features from
fmemory - runs health check using manifest
init_plan
- loads manifest/progress/features from
- Picks one highest-priority failing feature (
passes == false) - Delegates execution to
fchat(run_turnorstream_turn) - Validates outcome via
OutcomeValidator - Updates artifacts:
- marks feature passing only when validated
- appends progress entry
- records completed checkpoint with status/note
Integrated runtime and policy ownership
HarnessBuilder wires lower-layer runtime dependencies directly:
- provider (
fprovider) - chat service (
fchat) with transcript storage fromfmemory - tool runtime (
ftooling) - memory backend (
fmemory)
fchat stays responsible for turn orchestration. fharness owns run-level policy:
- phase selection (
initializervstask-iteration) - feature selection strategy (
FeatureSelector) - validation gate before marking feature pass (
OutcomeValidator)
Reliability + guardrails
Harness run policy now supports reliability constraints:
mode(strict_incremental,bounded_batch,unlimited_batch)max_turns_per_runmax_features_per_run(used by strict/bounded modes)retry_budget- fail-fast conditions (
health check,chat,validation)
Mode semantics:
strict_incremental: exactly one feature per run (max_features_per_runmust be1)bounded_batch: process up tomax_features_per_runfeatures in one rununlimited_batch: process features until completion gate or turn/retry constraints stop progress
Completion guardrail:
- harness does not declare done early
- completion requires all required features in
feature_listto havepasses = true
use std::sync::Arc;
use fharness::{Harness, RuntimeRunRequest, RuntimeRunOutcome};
use fmemory::{InMemoryMemoryBackend, MemoryBackend};
let memory: Arc<dyn MemoryBackend> = Arc::new(InMemoryMemoryBackend::new());
let harness = Harness::builder(memory)
.provider(provider)
.tool_runtime(tool_runtime)
.build()?;
match harness.run(RuntimeRunRequest::new(session, "run-1", "Build feature loop")).await? {
RuntimeRunOutcome::Initializer(_) => {
// session bootstrapped
}
RuntimeRunOutcome::TaskIteration(result) => {
// one task iteration completed
assert!(result.validated);
}
}
use std::sync::Arc;
use fharness::{Harness, TaskIterationRequest};
let harness = Harness::new(memory).with_chat(chat_service);
let request = TaskIterationRequest::new(session, "run-task-1");
let _result = harness.run_task_iteration(request).await?;
Extensibility hooks
HealthChecker- run startup/baseline checks before task-iteration work
OutcomeValidator- enforce real validation gates before marking features as passing
Use with_health_checker(...) and with_validator(...) to override defaults.
Clean handoff guarantees
Every task-iteration run records terminal outcome artifacts:
- run checkpoint with explicit
status(Succeeded/Failed) and note - progress entry summarizing what happened
This avoids ambiguous handoff state across context windows.
Error model
HarnessErrorKind variants:
InvalidRequestMemoryChatValidationHealthCheckNotReady
Dependencies
~35MB
~648K SLoC