feat!: every way in runs the new flow API; the old one is gone (U5) - #81
Merged
Merged
Conversation
A LocalEnv is this machine. An environment view on an ssh host passed for a LocalEnv-typed role was accepted by the per-call fast path and by _env(); both now refuse it with CapabilityMissing. The fast path pays one attribute test for auto roles only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ld API Every way in now runs flows written against hmz.flows through hmz.runtime.flowing's engine, and the previous flow API is gone. - hmz exec -f REF [-a ROLE=CLI[@Provider]/MODEL:EFFORT]... [-e ROLE=SPEC]... [-p KEY=VALUE]... -b duration=...,cost=...,output_tokens=... [--resume] [--json] TASK. -b is required except for the builtin chat, which runs under Budget(cost=inf). A role the flow does not declare, a runtime-filled role (Outworlder, LocalEnv) named on the line, a missing required role, an agent whose harness cannot fill its role, an unknown param, a bad spec, and --resume with nothing to pick up are usage errors (exit 2) before any agent starts. hmz exec is always away. -c/--config is gone; params are -p. - runtime.runner: read_line, Runner (static checks, drivers made last, environments probed before the flow is called), Refused, and a Recorder that writes a record per flow call under its caller, each session in the record of the call that opened it, and what the run spent. - runtime.epic hosts the engine journal as resume.jsonl; a resumed run is a new epic holding a copy of the journal it picked up. State/state.json are gone; picks_up/state/resumed read the journal. - Settings remember per flow the agent spec and env spec of each role, the params and the budget. kept.Runs is a CLI, an account, a model and an effort. - Hmz.run/runner/read/exec take roles; Run gains watch, opened, usage, budget, epic and result, stop() cancels the flow and close() also cuts every session. Flows.declared(ref) replaces places/check/prophecy/ foretell/configures; Flows.running() is the engine's running tree. - finding reads flows through the engine's loader; resolved() loads what a way in names and marks the flows humanize ships with full_view. BUILTIN_AT is hmz/flows/builtin, where the new-API chat lives: assistant (Agent, full harness view) and human (Outworlder), talking until the human says nothing. - The daemon's status carries the running tree; hmz.sdk offers Refused and the fakes. - hmz._legacy_flows and runtime/flowing/{checking,driving,prophecy, prophesying,stepping,proving} are deleted, with the tests that only tested them; the rest are ported to the new API. BREAKING CHANGE: flows written against the previous flow API no longer load, hmz exec takes roles and a budget, and settings and epics are written in the new shapes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The flow menu is one row per agent role the flow declares, with the roles the runtime fills (Outworlder, LocalEnv) left out and each role offered only the CLIs whose harness it names and whose capabilities it asks; one row per environment role, taking a spec as -e spells one; the flow's params, asked with its own params model; and a budget (duration, cost, output tokens, graceful), required for every flow but chat. - A run is Hmz.run with the interface as whoever is outside it: a question a flow puts to its outworlder is asked at the prompt and answered by the next line typed, and /afk makes it away. The transcript is drawn from Run.watch, each session's agent is learnt from Run.opened, and /stop is Run.stop, the third ctrl+c Run.close. A change made while a flow runs takes effect from the next run. - /resume carries on the last run here of a flow that can be picked up, from its journal; the running line reads the engine's running tree; the daemon's status is told the flow, its budget and its usage through Humanize.said. BREAKING CHANGE: what the interface remembers per flow is the new settings shape; the anchors and the unbounded-run question are gone. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Only the parts the switch-over contradicts: the temporary _legacy_flows clause of SPEC.md goes, and builtin flows live in flows/builtin; the runtime, doing, cli, tui and sdk specs describe the role-based hmz exec line, Runner, Run, the journal inside an epic, Flows.declared and the settings shape; flowing.md loses its legacy sections and gains resolved/builtin and the LocalEnv refusal. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
futrime
pushed a commit
that referenced
this pull request
Sep 25, 2026
… gone feat!: every way in runs the new flow API; the old one is gone (U5)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Unit 5 of the new flow API: every way into humanize --
hmz exec, the runtime facade, the TUI, the daemon and the SDK -- now runs flows through the new engine (hmz.flows+hmz.runtime.flowing), and the old flow API is gone.hmz exechmz exec -f <ref> [-a role=cli[@provider]/model:effort]... [-e role=backend@provider/workdir]... [-p key=value]... -b duration=...,cost=...,output_tokens=...[,graceful=...] [--resume] [--json] <task>-- every flag repeatable and comma-listable, read withspecs.py.-bis required (usage error, exit 2, before any agent starts) except for the builtinchat, which runs underBudget(cost=inf).Outworlder,LocalEnv) named with-a/-e, harness mismatch / capability the harness does not serve, bad spec, unknown or unreadable param, flow not found / will not import,--resumeof a non-resumable flow or with nothing to pick up, an env that cannot be reached (probed before the run).--resumepicks up the newest run of that flow in the workspace whose journal holds a call; without it every run starts fresh.hmz execis always "away" (open_outworlder()with noask).Run.watch→ every driver'swatch→cli.output.Shown);--jsonNDJSON is unchanged;-c/--configis gone (params are-p). A cost cap over a model nobody prices is said on stderr.Runtime
runner.py:read_line(thehmz execline),Runner(load viafinding.resolved, check roles/harness/capabilities/params/budget/resume statically, open drivers withopen_agent/open_env;arunprobes every env, thenrun_flowwith aRecorder, then closes every driver),Refused,Recorder(writes a record per sub-flow call under its caller, each session in the record of the call that opened it and named for its role, and the run's usage).epic.py: hosts the engine journal asresume.jsonl; a resumed run copies the journal into its own epic (picked_up);picks_up/state/resumedread the journal;State/state.jsonremoved;Rangainsref,envs,params,budget,picked_up;Droveis role + cli/provider/model/effort.settings.py/kept.py: per flow, role→agent spec (cli@provider/model:effort), role→env spec, params, budget.Hmz.read/runner/run/exectake roles;Rungainswatch,opened,usage,budget,epic,result;stop()cancels the flow task,close()also interrupts every session.Flows.places/check/prophecy/foretell/configures/set_up_fromare gone;Flows.declared(ref) -> Declaration;Flows.running()is the engine'srunning().finding.pyreads flows through the engine's loader (listing: the bare-ref flow under its module's name, other visible flows as<flow>:<sub>, hidden ones unlisted),resolved()loads what a way in names (marking flows humanize ships withfull_view),BUILTIN_ATishmz/flows/builtin.chat(new API) atsrc/hmz/flows/builtin/chat: rolesassistant: Agent(full harness view,online=ALL) andhuman: Outworlder,workspace: LocalEnv; loops agent turn → outworlder until the outworlder says nothing; a question the agent asks (ask-user hook) is put to the outworlder.LocalEnvrole given an environment on another machine is refused withCapabilityMissing, on both the fast path and_env().Daemon / SDK / TUI
flows(canonical refs) andcalls(the running tree: ref, name, depth, seconds, id, parent index); the TUI adds budget/usage throughHeld.says.hmz.sdkalso offersRefusedandfakes(hmz.runtime.flowing.fakes).src/hmz/tui/**): the flow menu is by role -- one row per agent role (auto roles hidden; CLIs offered only where the harness matchesrole.harnessand servesrole.capabilitiesperspi.HARNESS_CAPABILITIES), one row per non-auto env role taking an-espec, the params form (the existing pydantic-drivenConfiguressheet over the flow'sFlowParams), and a budget row (duration/cost/output tokens/graceful; required except chat). A run isHmz.run(...)withopen_outworlder(ask=..., away=...): an outworlder question is asked at the prompt and answered by the next typed line,/afkmakes it away; events come fromRun.watch, sessions' agents fromRun.opened;/stop=Run.stop(), third ctrl+c =Run.close();/resumecarries on the last run of a resumable flow from its journal; the running line uses the engine's running tree;Humanize.said()reports flow/budget/usage to the daemon status. The unbounded-run question and anchors view are gone.Deleted
src/hmz/_legacy_flows/**andruntime/flowing/{checking,driving,prophecy,prophesying,stepping,proving}.py, their lazy exports, and the tests that only tested them.Specs
specs/SPEC.md(legacy clause dropped; builtin flows live inflows/builtin),specs/runtime/SPEC.md,specs/runtime/doing.md,specs/runtime/flowing.md(legacy sections removed),specs/cli.md,specs/tui.md,specs/sdk.md(__all__).Tests
tests/recording.py, and 24 TUI test files (474 -> 465 functions).tests/system/runtime/test_exec.py(realclaudethroughhmz exec, chat without-b,--json), engine test for the LocalEnv refusal, runtime tests for the call tree/usage/stop/budget-stop, settings/kept tests, sdkfakestest.Test plan
uv run pre-commit run --all-filesuv run pytest(all three tiers)uv run pytest tests/system --run-agentshmz execplain/--json, epic + journal,--resume, usage errors,chatwithout-b.🤖 Generated with Claude Code