- INTENT.md: three-layer model (blueprint/instance/harness), single shared runtime, never-become boundaries - ADR-001 (accepted): DEC-2026-002 resolution — one harness repo for all projects; instances are declarative state in consuming repos - docs/architecture.md: components, contracts (manifest, tool profiles, completion events, credential lanes), deployment shape - agent_harness/: executor-worker prototype adopted and renamed (6/6 tests green); HARNESS-WP-0001 initial workplan (7 tasks) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
48 lines
1.6 KiB
Python
48 lines
1.6 KiB
Python
"""Task specification the worker consumes.
|
|
|
|
MVP source is a JSON file matching what the activity-core issue-core sink
|
|
emits per rule action (task_template/description/target_repo/labels), plus
|
|
executor-specific fields. A future source polls issue-core directly.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import dataclass, field
|
|
from pathlib import Path
|
|
|
|
|
|
class TaskSpecError(ValueError):
|
|
pass
|
|
|
|
|
|
@dataclass
|
|
class TaskSpec:
|
|
title: str
|
|
description: str
|
|
target_repo: Path
|
|
agent: str = "coach"
|
|
labels: list[str] = field(default_factory=list)
|
|
hub_task_id: str | None = None
|
|
completion_event_type: str = "executor_run"
|
|
timeout_seconds: int = 900
|
|
|
|
@classmethod
|
|
def from_file(cls, path: str | Path) -> "TaskSpec":
|
|
raw = json.loads(Path(path).read_text())
|
|
missing = {"title", "description", "target_repo"} - set(raw)
|
|
if missing:
|
|
raise TaskSpecError(f"task spec missing field(s): {', '.join(sorted(missing))}")
|
|
target = Path(raw["target_repo"]).expanduser()
|
|
if not (target / ".git").is_dir():
|
|
raise TaskSpecError(f"target_repo is not a git repository: {target}")
|
|
return cls(
|
|
title=str(raw["title"]),
|
|
description=str(raw["description"]),
|
|
target_repo=target,
|
|
agent=str(raw.get("agent", "coach")),
|
|
labels=[str(label) for label in raw.get("labels", [])],
|
|
hub_task_id=raw.get("hub_task_id"),
|
|
completion_event_type=str(raw.get("completion_event_type", "executor_run")),
|
|
timeout_seconds=int(raw.get("timeout_seconds", 900)),
|
|
)
|