No description
  • Rust 45.7%
  • JavaScript 19.3%
  • Python 16.8%
  • HTML 13.2%
  • CSS 4.9%
Find a file
mik-tf 7f43175aa7
All checks were successful
lab publish / publish (push) Successful in 12m5s
ci: install lab onto PATH from ~/.local/bin in the publish workflow
The lab installer now installs to ~/.local/bin instead of ~/hero/bin.
Point GITHUB_PATH at the new location so the release publish works again.

Signed-by: mik-tf <mik-tf@noreply.invalid>
2026-05-29 15:42:31 -04:00
.forgejo/workflows ci: install lab onto PATH from ~/.local/bin in the publish workflow 2026-05-29 15:42:31 -04:00
crates fix(hero_logic_sdk): use literal unix socket URL in generated connect() instead of resolve_socket_path_with_override 2026-05-27 01:24:40 +02:00
examples chore(hero_logic): rename FORGEJO_TOKEN→FORGE_TOKEN and HERO_SOCKET_DIR→PATH_SOCKET 2026-05-26 12:43:45 +02:00
scripts chore(bakeoff): split med_ok / med_all, add attempts + diagnosis columns 2026-05-14 12:06:03 +02:00
.gitignore feat(11-E): seed service_agent_v3 Python flow on startup (#22) 2026-05-06 17:35:14 +00:00
buildenv.sh refactor: rename hero_logic_ui -> hero_logic_admin (ui.sock -> admin.sock) (#26) 2026-05-08 02:06:06 +00:00
Cargo.lock refactor(hero_logic): extract OpenRPC client SDK into hero_logic_sdk crate 2026-05-25 12:30:54 +02:00
Cargo.toml refactor(hero_logic): extract OpenRPC client SDK into hero_logic_sdk crate 2026-05-25 12:30:54 +02:00
Cargo.toml.hero_builder_backup chore(hero_logic): pin hero ecosystem deps to v0.6.0, add rust-version, refactor base_path middleware 2026-05-24 16:01:26 +02:00
PRD.md chore(hero_logic): rename FORGEJO_TOKEN→FORGE_TOKEN and HERO_SOCKET_DIR→PATH_SOCKET 2026-05-26 12:43:45 +02:00
PURPOSE.md chore(hero_logic): rename FORGEJO_TOKEN→FORGE_TOKEN and HERO_SOCKET_DIR→PATH_SOCKET 2026-05-26 12:43:45 +02:00
README.md chore(hero_logic): rename FORGEJO_TOKEN→FORGE_TOKEN and HERO_SOCKET_DIR→PATH_SOCKET 2026-05-26 12:43:45 +02:00

hero_logic

A runtime for runnable, observable, resumable Python flows.

A flow is a Python function decorated with @flow(...). It has typed inputs and outputs. When you run it, hero_logic spawns a sandboxed Python subprocess, captures a live span tree of every step, persists the result, and renders the run as a graph you can read at any depth.

Flows compose recursively: a step calls another flow as a function (in-process, default) or as a separate Play (spawned, opt-in). Any step at any depth can pause — exit cleanly with state persisted — to wait for input from a user, a webhook, a scheduled trigger, or any other source. When a resume arrives, the play re-runs; every previously-completed step replays from cache, the pause returns the resume payload, execution continues. No long-blocked subprocesses, no lost work, no double side-effects.

Around the runtime: versioned workflows, saved input presets, per-version benchmarks, a searchable library of flows, and a web admin with Monaco source + live graph view + pause/resume input forms.

For the full design see PRD.md. This README is the orientation.


What problems it solves

  • Visibility into multi-step automation. Watch a complex run, live, as a tree — including nested sub-flows, fan-outs, retries, replays. A reader who doesn't know Python can still see what happened.
  • Resumable workflows without long-running processes. A flow can ask a user for a clarification, wait for an external webhook, or pause for a scheduled trigger — and the subprocess exits cleanly until the resume arrives.
  • Reproducible runs with cost / latency tracking. Pin Plays to specific versions; benchmark versions against realistic inputs; let the runtime pick the right version per request based on cost/speed/accuracy weights.
  • A growing library of solved problems. Every saved Workflow is a callable primitive. The agent searches the library before generating fresh code; user-confirmed flows save back as reusable entries.

The dominant current consumer is AI-agent orchestration (service_agent and friends), but hero_logic is not AI-specific. Anything that benefits from typed I/O + step visibility + saved inputs + benchmarks + pauses qualifies.


Core API (Python)

Authoring surface, all exported from hero_tracing:

from hero_tracing import flow, instrument, ask_user

@flow(name="my_flow", inputs={"prompt": {"type":"string","required":True}},
 outputs={"answer": {"type":"string"}})
def main(prompt):
 ai = instrument(HeroAibrokerClient()) # opt-in per-RPC spans

 selection = flow.invoke("pick_service", prompt=prompt) # in-process sub-flow
 if not selection["confident"]:
 selection = ask_user.choice("Which service?", # pause for human input
 options=selection["candidates"])

 result = flow.invoke("run_against_service", # spawned sub-flow → own Play
 service=selection, prompt=prompt, spawn=True)
 return {"answer": result["summary"]}
  • @flow — every call becomes a span; declares typed I/O; outputs are memoized for replay
  • flow.step(name, **tags) / flow.span(...) — context-manager spans (use sparingly; prefer @flow)
  • flow.invoke(name, **inputs, spawn=False) — call a sub-flow (in-process or spawned)
  • flow.pause(name, schema=..., ui=...) — generic pause; returns the resume payload
  • ask_user.text / number / choice / multi_choice / confirm — UI-flavored helpers over flow.pause
  • instrument(client) — opt-in per-RPC spans
  • flow.Failed — clean "this didn't work" exception for spans
  • flow.current_span.tag(k, v) / .log(text) — attach data to the current span

See PRD §3 for the full surface.


RPC surface (LogicService)

JSON-RPC 2.0 over HTTP/1.1 over UDS at ~/hero/var/sockets/hero_logic/rpc.sock. Generated typed clients live at ~/.hero/var/router/python/hero_logic_client.py.

workflow_create / workflow_get / workflow_list / workflow_update / workflow_delete
workflow_create_version / workflow_set_current_version / workflow_version_fetch
play_start / play_run_async / play_status / play_wait / play_cancel
play_resume / play_pending_resumes
example_upsert / example_fetch / example_to_input_data / example_list / example_delete
benchmark_list_for_workflow / benchmark_list_for_version / benchmark_latest_for_version
pick_version
flow_library_search

See PRD §8 for parameters and return shapes.


Where things live

hero_logic/
├── PRD.md # full design spec
├── README.md # this file
├── examples/ # E2E driver scripts (start play, respond to pauses, assert)
└── crates/
 ├── hero_logic/ # CLI binary + RPC server binary + executor
 │ ├── src/main.rs # hero_logic CLI (--start / --stop / --info)
 │ ├── src/bin/hero_logic_server.rs # JSON-RPC server (rpc.sock)
 │ ├── src/engine/ # Python executor, span socket, replay
 │ ├── src/seed_flows/ # bundled @flow Python sources
 │ ├── schemas/logic/logic.oschema # types + RPC source of truth
 │ └── sdk/python/hero_tracing.py # embedded; staged on server startup
 └── hero_logic_admin/ # Axum dashboard (admin.sock)
 ├── src/main.rs
 └── templates/ # Askama HTML

Runtime paths the executor touches:

  • ~/hero/var/sockets/hero_logic/{rpc.sock,admin.sock} — service sockets
  • ~/.hero/var/flows/sdk/hero_tracing.py — staged on every server start
  • ~/.hero/var/router/python/ — generated RPC clients (owned by hero_router)
  • ~/.hero/var/plays/{play_sid}/work/ — per-Play workdir + replay cache files
  • /tmp/spans-{play_sid}.sock — per-Play span socket

Binaries

Binary Kind Socket Purpose
hero_logic cli Registration + control (--start / --stop / --info)
hero_logic_server server hero_logic/rpc.sock JSON-RPC, executor, span listener
hero_logic_admin admin hero_logic/admin.sock Web dashboard

All three follow the herolib_base pattern: service.toml at the crate root, embedded via service_base!(), validated and printed on startup, sockets prepared and stale-cleaned before bind. See PRD §13.


Build, install, run

lab reads each binary's service.toml and drives the whole build / install / start / stop lifecycle on top of hero_proc:

lab service logic --install # build + install all declared binaries to ~/hero/bin
lab service logic --start # register with hero_proc and start server + admin
lab service logic --status # status of all binaries
lab service logic --stop # stop all binaries

For local development without hero_proc, run a binary directly:

RUST_LOG=debug cargo run -p hero_logic --bin hero_logic_server # server in foreground
cargo run -p hero_logic_admin # admin UI in foreground
cargo test --workspace # tests

hero_proc must be running before lab service logic --start. Admin UI: http://localhost:9820 when proxied through hero_router, or via ~/hero/var/sockets/hero_logic/admin.sock.


How a run flows end-to-end

  1. Author writes a @flow-decorated Python function; saves as a Workflow + first WorkflowVersion.
  2. play_start validates inputs, writes a Play, binds /tmp/spans-{sid}.sock, spawns python3 with PYTHONPATH pointing at the staged SDK + generated clients.
  3. The subprocess imports hero_tracing, the boot stub calls the @flow-decorated entry; every step emits JSONL span events over the socket.
  4. The server persists spans incrementally and pushes them via SSE to the admin UI's graph view.
  5. If a step calls flow.pause(...) → subprocess exits clean, Play.status = awaiting_resume, a ResumeRequest is persisted.
  6. UI (or webhook / cron / another service) calls play_resume(play_sid, resume_id, payload) → server spawns a fresh subprocess; cached step outputs short-circuit @flow calls; the pause returns the resume payload; the run continues. Repeats per pause until the play reaches a terminal status.

For details on the replay contract and step memoization, see PRD §45.


Tips for AI agents picking this up

  • The PRD is the source of truth. Read it before changing anything structural.
  • crates/hero_logic/schemas/logic/logic.oschema is the source of truth for types + RPC. Edit the schema, regenerate, then implement handlers — not the other way around.
  • The Python authoring surface is crates/hero_logic/sdk/python/hero_tracing.py. Wire protocol lives there too.
  • The executor is crates/hero_logic/src/engine/python_executor.rs (spawn, sandbox, boot stub) and engine/span_socket.rs (listener, persistence).
  • Seed flows in crates/hero_logic/src/seed_flows/ are working reference implementations of the authoring patterns. service_agent.py is the primary example.
  • /examples/ is the E2E test surface — runnable scripts that drive a play through its full lifecycle including resumes.

License

Apache-2.0