Skip to main content
CLI entry point — the batch shell. main() drives the real loop via run_agent. The CLI stays a thin shell over the loop — wiring components and event subscribers, nothing more. It is deliberately TUI-free: the harness is an independent core under many consumers, and the interactive cockpit ships as a separate jo-cli package (the jo command) so the import direction stays strictly consumer → core.

Functions

main(argv: list[str] | None = None, *, config: HarnessConfig | None = None, model_client: ModelClient | None = None, task_kind: Literal['edit', 'investigate', 'test_only'] = 'investigate') -> int

CLI entry point: parse args, wire the loop, run the task, render the artifact. Args: argv: Argument vector; falls back to sys.argv when omitted. config: Harness config; constructed from the environment when omitted. model_client: Model client; a default OpenAIModelClient if omitted (injectable for tests). task_kind: The verification contract to apply (investigate / edit / test_only). Returns: Process exit code: 0 on success, 2 on a dirty workspace, 1 otherwise.

run_agent(task: str, *, config: HarnessConfig, emitter: Emitter, model_client: ModelClient | None = None, allow_dirty: bool = False, task_kind: Literal['edit', 'investigate', 'test_only'] = 'investigate') -> TaskState

Run the agent loop over task. Args: task: The natural-language task to run. config: Harness config wiring the loop. emitter: Sink for observation events. model_client: Model client; a default OpenAIModelClient if omitted. allow_dirty: When True, open the workspace despite uncommitted tracked changes (§15). task_kind: The verification contract to apply (investigate / edit / test_only). Returns: The terminal TaskState after the loop settles.