Generalize Coder harness to reusable Harness abstraction

t-315·WorkTask·
·
·
·Omni/Agent/Harness.hs
Created1 month ago·Updated1 month ago

Dependencies

Description

Edit

Summary

After simplifying to just Coder (t-314), generalize the Coder harness pattern into a reusable abstraction. The Coder is valuable because of its programmatic lifecycle (init → work → verify → commit/rollback), not because it's specifically for coding.

The Pattern

The Coder harness follows this lifecycle:

┌─────────┐     ┌─────────┐     ┌─────────┐     ┌─────────┐
│  Init   │ ──► │  Work   │ ──► │ Verify  │ ──► │ Commit  │
└─────────┘     └─────────┘     └─────────┘     └─────────┘
     │               │               │               │
     ▼               ▼               ▼               ▼
  Check env      Agent loop     Programmatic     Finalize
  Detect state   with tools     validation       or rollback

This pattern could apply to other domains:

  • Database migrations: init (backup) → work (write migration) → verify (dry run) → commit (apply)
  • Infrastructure changes: init (plan) → work (generate) → verify (validate) → commit (apply)
  • Document generation: init (gather context) → work (draft) → verify (check constraints) → commit (publish)

Proposed Abstraction

-- Omni/Agent/Harness.hs

data HarnessConfig a = HarnessConfig
  { harnessName :: Text
  , harnessInit :: IO (Either Text a)           -- Setup, returns context
  , harnessVerify :: a -> IO VerifyResult       -- Programmatic validation
  , harnessCommit :: a -> Text -> IO (Either Text ())  -- Finalize
  , harnessRollback :: a -> IO ()               -- Cleanup on failure
  , harnessTools :: [Engine.Tool]               -- Tools available during work phase
  , harnessSystemPrompt :: a -> Text            -- Prompt with context
  , harnessMaxVerifyRetries :: Int
  }

data VerifyResult
  = VerifySuccess
  | VerifyFailed Text  -- Error message for agent to fix

runHarness :: Text -> HarnessConfig a -> Text -> IO (Either Text HarnessResult)

Coder as a Harness Instance

coderHarness :: CoderConfig -> HarnessConfig CoderContext
coderHarness cfg = HarnessConfig
  { harnessName = "coder"
  , harnessInit = runCoderInit cfg
  , harnessVerify = \_ -> runCoderVerify cfg  -- lint, build, test
  , harnessCommit = \_ summary -> runCoderCommit cfg summary
  , harnessRollback = \_ -> runCoderRecovery (coderWorkDir cfg)
  , harnessTools = coderTools
  , harnessSystemPrompt = coderSystemPrompt cfg
  , harnessMaxVerifyRetries = coderMaxVerifyRetries cfg
  }

Benefits

1. Reusability: New harnesses can be created by implementing the interface 2. Consistency: All harnesses follow the same lifecycle 3. Testability: Each phase can be tested independently 4. Extensibility: Add new harnesses without changing core infrastructure

Steps

1. Create Omni/Agent/Harness.hs with the abstraction 2. Refactor Coder to use the harness 3. Verify Coder still works 4. Document how to create new harnesses

Future Harnesses (not in scope, just examples)

  • DatabaseMigration harness
  • InfrastructureChange harness
  • DocumentPublish harness

Acceptance Criteria

  • [ ] Omni/Agent/Harness.hs created with HarnessConfig type
  • [ ] runHarness function implements the lifecycle
  • [ ] Coder refactored to use harness abstraction
  • [ ] Coder still works via Telegram
  • [ ] Documentation on creating new harnesses

Timeline (2)

🔄[human]Open → InProgress1 month ago
🔄[human]InProgress → Done1 month ago