Skip to content

feat(cli): panda workflow — workflow-engine passthrough + docs#290

Open
Savid wants to merge 3 commits into
masterfrom
feat/workflow-cli
Open

feat(cli): panda workflow — workflow-engine passthrough + docs#290
Savid wants to merge 3 commits into
masterfrom
feat/workflow-cli

Conversation

@Savid

@Savid Savid commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary

Adds a panda workflow CLI command group: a thin, curated CRUD + SSE-streaming client over an external workflow-engine REST API, routed through the local panda server and the credential proxy. It lets an agent turn a plain-language request into a completed workflow run (whiteboard → session → draft → publish → run → follow → outputs → steer).

The CLI never sees a workflow-engine token. Requests route server /api/v1/workflow/*proxy /workflow/*; the proxy holds the bearer (or forwards the user's own in passthrough mode). The server and CLI never handle it — the same trust shape as other proxy-credentialed upstreams.

Design compliance (per AGENTS.md guardrails)

  • Not a module — the module registry (pkg/app/app.go) is unchanged.
  • No new MCP tool — the 3-tool surface (execute_python, manage_session, search) is unchanged.
  • No caller-identity branching — docs content is dialect-rendered via surface.Dialect (CLI gets the full guide; MCP gets a CLI-only stub with no CLI-flag syntax).
  • Docs resources are not in the search index (built from explicit registries, not the resource registry).

What's included

  • Proxy (pkg/proxy/handlers/workflow.go, server_config.go, router.go): a /workflow/* handler with fail-closed token injection, path clamp/clean with ../%2e%2e/..;/backslash rejection re-verified after path.Clean, a strict header allow-list, SSE-safe flushing (FlushInterval:-1 + DisableCompression), a 502 ErrorHandler, and a request metric emitted on completion.
  • Server (pkg/server/workflow.go, api.go, builder.go): a thin httputil.ReverseProxy passthrough at /api/v1/workflow/* — disabled→503 short-circuit, explicit upstream path rewrite, inbound Authorization/Cookie/Host/attribution stripped.
  • Config (pkg/config/config.go, config.example.yaml, proxy-config.example.yaml): workflow-engine base URL / auth settings; enabled iff the base URL is set; validation rejects userinfo/path/query/fragment/out-of-range-port/unknown auth mode. Example blocks ship commented out (base URL is the enable marker) with a restart note.
  • CLI (pkg/cli/workflow*.go): noun-verb commands for whiteboard, session, draft, workflow/run, steer, artifact, dispatch/agent/worker, docs, and a raw api escape hatch. Percent-encoded path segments, UUIDv4 Idempotency-Key (with --idempotency-key override), --out for artifact bytes, NDJSON under --json, a bounded SSE frame parser, a run-stream status→exit-code contract, and RFC 7807 problem+json + text/plain error hints.
  • Docs (pkg/resource/workflow.go, workflowdocs/): workflow://guide + workflow://api server resources (panda workflow docs [api]), a CLI-only getting-started section, and an AGENTS.md entry.
  • Removes the legacy uploads/assets-CLI surface this supersedes.

Verification

  • go build ./... passes.
  • The full acceptance/streaming/coverage suites from the prior iterations carry over unchanged (the code content is identical to the validated tip of the previous branch, plus the proxy-passthrough URL handling and its tests).

⚠️ Boundary-owner sign-off required before merge

These are doc/sign-off obligations, not defects — the code is consistent with them:

  1. New class of credentialed, mutating upstream reached via the server + proxy. Requires explicit boundary-owner sign-off.
  2. The raw api hatch reaches the full upstream surface with the injected token — by design; use a least-privilege (non-root) principal.
  3. Bind the server to loopback where it fronts this credentialed upstream on the unauthenticated /api/v1 surface.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

🐼 Smoke eval — 619bd42: ✅ 8/8 pass

📊 Interactive report — tokens p50 19,171 · tokens/solve 21,324.

Reference points: feat/workflow-cli@d8179b3 88% · master@cfe9bbd 100% · feat/workflow-cli@b051101 100%.

question result tokens tools
forky_node_coverage 15,779 7
tracoor_node_coverage 16,681 6
mainnet_block_arrival_p50 16,776 8
list_datasources 13,136 2
block_count_24h 21,566 9
missed_slots_24h 25,598 22
chartkit_default_arrival_distribution 39,274 18
storage_upload_session_scoped 21,781 15
🔭 Langfuse traces (8 runs; ⚠️ = failed)

The report walks this branch's commits against the master baseline and the most recent release. A self-contained copy is in the run's eval-smoke-* artifact.

Savid and others added 2 commits July 8, 2026 12:45
Add a `panda workflow` CLI command group: a curated CRUD + SSE-streaming
client over the external workflow engine's REST API, routed through the
local panda server and the credential proxy. It lets an agent turn a
plain-language request into a completed workflow run (whiteboard →
session → draft → publish → run → follow → outputs → steer).

The CLI never sees a workflow-engine token. Requests route
`server /api/v1/workflow/*` → `proxy /workflow/*`; the proxy holds the
bearer (or forwards the user's own in passthrough mode). The server and
CLI never handle it — the same trust shape as other proxy-credentialed
upstreams.

Design compliance (per AGENTS.md guardrails):
- Not a module — the module registry is unchanged.
- No new MCP tool — the 3-tool surface (execute_python, manage_session,
  search) is unchanged.
- Docs resources are dialect-rendered via surface.Dialect (CLI gets the
  full guide; MCP gets a CLI-only stub) with no caller-identity branching.

Includes:
- Proxy: `/workflow/*` handler with fail-closed token injection, path
  clamp/clean with traversal rejection, strict header allow-list,
  SSE-safe flushing, and request metrics.
- Server: thin reverse-proxy passthrough at `/api/v1/workflow/*`.
- pkg/workflowrelay: shared relay contract (header allow-list, traversal
  rejection, problem+json) used by both hops.
- Config: workflow-engine base URL / auth settings with validation, and
  proxy auth.scopes for passthrough mode; example blocks ship commented.
- CLI: noun-verb commands for whiteboard, session, draft, workflow/run,
  steer, artifact, dispatch/agent/worker, `docs`, and a raw `api` escape
  hatch, with percent-encoded path segments, idempotency keys, `--out`
  for artifact bytes, NDJSON under `--json`, a bounded SSE frame parser,
  and a run-stream status→exit-code contract.
- Docs: `workflow://guide` + `workflow://api` server resources
  (`panda workflow docs [api]`) and an AGENTS.md entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…route, 401 hint

- server relay: preserve a base path on the proxy URL (a proxy mounted
  under a subpath) instead of overwriting it, matching the string-concat
  join every other proxy call uses
- run follow: the reconnect budget bounds CONSECUTIVE fruitless attempts;
  a stream that delivered an event resets it, so long runs behind an
  idle-timeouting LB are not capped at 10 drops over their lifetime
- server relay: route bare /api/v1/workflow to the engine API root so
  'panda workflow api GET /' is not a misleading 404
- CLI: key the 401 proxy-vs-engine hint on the proxy's exact
  writeBearerError phrases instead of the substring "proxy" (which the
  proxy's real 401 bodies never contain)
- proxy: drop the dead handlers.WorkflowConfig.AllowedOrgs field
  (enforcement lives in the authorizer)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Savid Savid force-pushed the feat/workflow-cli branch from d8179b3 to b051101 Compare July 8, 2026 02:54
…, api cmd file split

- deflake TestWorkflowHandlerUpstreamDownReturns502: inject a failing
  transport instead of relying on a closed httptest port staying unbound
  (a concurrent test's server can re-bind it, turning the dial error
  into a live 404)
- auth-retry header reset restores the pre-relay baseline instead of
  clearing to empty, so middleware-set response headers survive while a
  trapped 401's stale upstream headers are still dropped; test added
- move workflowAPICmd + helpers out of workflow_docs.go into
  workflow_api.go, whiteboard-id completer into workflow_whiteboard.go
  (pure relocation)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant