// Command harness is the CLI entry point: flag parsing, wiring, and (from
// Phase 1) the REPL.
package main
import (
"encoding/json"
"flag"
"fmt"
"os"
"path/filepath"
"time"
"harness/internal/metrics"
"harness/internal/tools"
)
func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, "harness:", err)
os.Exit(1)
}
}
func run() error {
workdir := flag.String("C", ".", "working root the agent operates in")
logPath := flag.String("metrics", metrics.DefaultPath, "JSONL event log path")
flag.Parse()
root, err := filepath.Abs(*workdir)
if err != nil {
return err
}
session := time.Now().UTC().Format("20060102T150405Z")
log, err := metrics.Open(filepath.Join(root, *logPath), session)
if err != nil {
return err
}
defer log.Close()
log.Log(metrics.Event{Type: "session_start", Extra: map[string]any{"root": root}})
reg := tools.NewRegistry(log)
// Tools land here in Phase 1 (read_file) and Phase 2 (the rest).
fmt.Printf("harness session %s\nroot: %s\nmetrics: %s\ntools: %d registered\n",
session, root, filepath.Join(root, *logPath), len(reg.List()))
for _, t := range reg.List() {
schema, _ := json.Marshal(json.RawMessage(t.InputSchema()))
fmt.Printf(" %-12s %s\n %s\n", t.Name(), t.Description(), schema)
}
fmt.Println("\nno agent loop yet — Phase 1.")
return nil
}