picatz / picatz/flowstate

flow controlling flow: the reflexive plugin, self-building workloads, and the governance that makes it safe

Open
#174 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

design engine kind/design-record
Dominant language
Go
Stars
9
Forks
0
Avg merge
3h 3m
Merged PRs (30d)
509

Description

The system's control plane is itself a set of typed RPCs over a client-neutral IR — which means workflows can operate it. A first-class flowstate plugin (start runs, signal runs, query state, cancel, list — through the front door, with policy applied) turns the platform reflexive: workflows that orchestrate workflows, agents that manage fleets of runs, operators encoding their runbooks as runs. This is the "factory for any workload shape" capstone, and it's also the feature that most needs its governance stated before it exists, because a reflexive control surface amplifies whatever authority model it inherits.

Why this is the natural next composition, not scope creep

  • #162 already commits to the first verb: flowstate.signal, run-to-run communication through the front door. The full plugin is that decision carried to its conclusion — every verb the CLI has, available as a task, same RPCs, same auth, same policy. No back door: the plugin is a client, indistinguishable from any other, which is what keeps the security analysis tractable.
  • call: composes workflows within a spec (static, compile-time, vendored). The reflexive plugin composes runs (dynamic, runtime, policy-gated). Those are the two composition modes a real platform needs, and keeping them distinct — rather than blurring call: into runtime resolution — is what lets each stay clean (#172's whole argument).
  • Detached starts (#166 gap 2) land here for free: flowstate.run with no wait is the detached start — a first-class run, listable, cancelable, findable by id from the parent's outputs.

Self-building workloads, honestly

Since the IR is protobuf and the submission path validates hermetically, a workflow can construct a workflow — an agent authoring a spec, validating it, submitting it, watching it. That's the self-building-agent shape, and the guardrails are the ones that already exist, applied without exception: a generated spec passes the same validation, size bounds, and policy as a hand-written one; it runs under the tenant and identity of whoever submitted it, with no ambient escalation; and the authority to submit at all is a policy decision (below). A generated workflow is not a special case — that's the design: one IR, one gate, any author (human, agent, or run).

The governance substrate this rides on (mostly built, needs naming as a product surface)

Multi-tenancy (namespaces, per-tenant secret scoping, tenant-isolated listing) — built. AuthN via workload identity, JIT/WIF federation — built (#115), expanding per #173. Policy as compiled, fail-closed CEL — built across egress/auth/secrets. What the reflexive plugin adds to the demands list, in order:

  1. Control-plane authorization granularity: today's policy answers "may this identity call this RPC"; reflexive use sharpens it to "may this run start runs of what, in which namespace, at what rate" — CEL rules over (caller identity, caller run context, target spec attributes like digest per #172's item 1). Rate/count bounds are the new piece: a workflow that starts workflows is a fork bomb with a policy problem, so the bound on runs started per run is a first-class policy input, not an afterthought.
  2. Depth/lineage: reflexive starts carry lineage (parent run id chain) so the equivalent of MaxCallDepth exists across runs, observably — and so an operator can trace a fleet back to the run that spawned it (#166's "detached is not untracked" rule, enforced by schema).
  3. Humans in the loop are already a primitive: wait_for_signal + the select shape (#166 shape 6) means "agent proposes, human approves, fleet proceeds" is a workflow, not a bolt-on approval system. The RBAC question "who may send that approval signal" is the same control-plane authorization as item 1 — one policy language throughout, which is exactly the "flows naturally for humans and agents alike" property: nothing new to learn per surface.

Discipline

The plugin's verb set starts minimal — signal (#162, committed), then run/get/cancel when the multi-agent example needs them — each through the existing RPCs with zero new server surface. The fork-bomb policy bound lands with run, not after it (fail closed from the first day the verb exists). Lineage rides the existing memo/search-attribute machinery. Everything else here is named-not-scheduled per the standing rule, waiting on the #162 demo and real multi-tenant demand to pull it.

Related: #162 (agents-as-runs), #166 (topology; gap 2 detached starts, shape 6 select), #172 (call: vision — the static half), #173 (credential invisibility — the authority these runs act with), #157 (language slate).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the related issues #162, #166, #172, and #173, then trace the existing typed RPC, policy, lineage, and CLI entry points they reference. This issue names no files or tests; it is done when the minimal plugin scope, authorization and rate bounds, lineage rules, and sequencing are agreed.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend-api-design, distributed-systems, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.