embed: `RunOptions` exposes inputs, tasks, a clock and a signal waiter, and none of the observer, debugger, logger, policy or telemetry seams the engine already has
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 9
- Forks
- 0
- Avg merge
- 3h 3m
- Merged PRs (30d)
- 509
Description
Observed behavior
pkg/flowstate/embed/run.go:30 at eb8172f:
type RunOptions struct {
Inputs map[string]any
Tasks *Tasks
Clock v1.Clock
Signals v1.SignalWaiter
}
The engine underneath has more seams than that, each already used by a first-party surface:
v1.Debugger(pkg/flowstate/v1/debugger.go:79) andv1.RunObserver, whichflowdebug.Sessionimplements to step a run and see what each step produced. An embedder who wants a progress callback, a per-step hook for their own UI, or to attach the debugger to a run they own has no field to put it in.- The task runtime's secret store, secret policy and credential broker (
engine.NewTaskRuntimeConfig), whichRunDurableaccepts as a variadic andRunLocaldoes not, so a local run in an embedder cannot resolve a secret under a policy while a durable one can.embed.Secretsexists beside it and the two are not the same object. - The egress policy, task-shape policy and audit sink the CLI wires for
flow run local(cmd/flow/egress.go,taskpolicy.go), none of which an embedder can set, soflow run local --egress-policyis a posture the facade cannot rehearse. - The
slog.Loggerand the OpenTelemetry tracer the CLI installs, so an embedded run logs to the default logger and emits no spans into the host program's trace.
The facade's own doc says it is "a curated surface, not a Go compatibility promise" (docs/EMBEDDING.md:17), which is the right posture for adding these deliberately rather than exposing the engine.
Desired outcome
RunOptions gains Observer v1.RunObserver, Debugger v1.Debugger, Logger *slog.Logger, Tracer trace.Tracer (or the provider), and one Policy struct carrying egress, task-shape, secret policy and an audit sink, each defaulting to what RunLocal does today. RunDurable accepts the same Policy so the two drivers are configured by one object, per invariant 3.
Acceptance criteria
- An
Exampletest attaches an observer that records step ids and asserts the order for a three-step file. - An
Exampletest attachesflowdebug.NewSessionthroughDebuggerand replays a two-line script, proving the debugger is a library brick and not only a CLI mode. - A test runs a workflow with an
httpstep under an egress policy that denies the host and asserts the same refusalflow run local --egress-policyprints. - Spans from an embedded run appear under the host program's tracer, pinned by an in-memory exporter test.
Constraints and dependencies
- Adjacent: #230 (the facade design), #1557 (task error classification), #1674 (the facade's doc gaps), #928 (the debugger as a surface), #1652 (redaction reachable outside the CLI).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with docs/EMBEDDING.md and pkg/flowstate/embed/run.go, then trace RunLocal, RunDurable, and engine.NewTaskRuntimeConfig alongside cmd/flow/egress.go and taskpolicy.go. Add focused Example and exporter tests for observer ordering, debugger replay, denied egress, and tracing, using the existing CLI behavior as the reference. Done means both drivers accept the shared configuration and all four acceptance criteria pass.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- api, backend, observability, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 42/100