Skip to content

feat: Implement workflow generation command with YAML validation and LLM integration#37

Open
krishvsoni wants to merge 1 commit into
open-gitagent:mainfrom
krishvsoni:feat/issue-9-workflow-llm-generator
Open

feat: Implement workflow generation command with YAML validation and LLM integration#37
krishvsoni wants to merge 1 commit into
open-gitagent:mainfrom
krishvsoni:feat/issue-9-workflow-llm-generator

Conversation

@krishvsoni
Copy link
Copy Markdown

Implemented workflow generation command with YAML validation and LLM integration

Resolves #9

What changed

New files

File Purpose
spec/schemas/workflow.schema.json JSON Schema describing SkillFlow workflows. Single source of truth used by both the validator and the LLM system prompt.
src/utils/schemas.ts loadWorkflowSchema(), getWorkflowSchemaText(), validateWorkflow(yamlText) → { valid, errors[], data? }. Hand-rolled validator (no new deps).
src/utils/workflow-generator.ts generateWorkflow({ prompt, skills, previousWorkflow?, model?, apiKey?, llm? }) — builds the system prompt + two few-shot pairs (linear pipeline, approval step), calls the LLM, strips code fences, returns YAML. llm is injectable so tests don't hit the network.
src/commands/workflow.ts CLI: gitclaw workflow generate with -d / -p / --refine / -m / --api-key / --dry-run. Runs the 2-retry validation loop and writes workflows/<slug>.yaml.
test/workflow-validator.test.ts 11 unit tests for the validator.
test/workflow-generator.test.ts 13 unit tests for prompt assembly, fence stripping, retry loop, dry-run, and refine mode (LLM mocked).
test/ts-resolve-hook.mjs Tiny ESM resolve hook so node --experimental-strip-types can follow Node16-style .js internal imports during tests.

Modified files

File Change
src/index.ts Added import { handleWorkflowCommand } and an early-dispatch branch for gitclaw workflow … (mirrors the existing gitclaw plugin … pattern).
package.json test script preloads the resolve hook so npm test works out of the box.

CLI surface

# Generate from scratch (writes workflows/<slug>.yaml)
gitclaw workflow generate -p "every morning summarize unread emails and post to Slack"

# Iteratively refine an existing workflow
gitclaw workflow generate \
  --refine workflows/morning-email-digest.yaml \
  -p "add a human approval step before the Slack post"

# Preview without writing
gitclaw workflow generate -p "..." --dry-run

# Override model / key
gitclaw workflow generate -p "..." -m anthropic:claude-sonnet-4-5 --api-key sk-...

Why these choices

1. Schema on disk, not inlined

Single source of truth. spec/schemas/workflow.schema.json is loaded at runtime and embedded verbatim into the LLM system prompt — the validator and the generator cannot drift.

2. Hand-rolled validator (no AJV)

Zero new deps. AJV isn't in package.json; rather than add ajv + ajv-formats, the validator implements only what this schema needs (type, required, additionalProperties, pattern, minItems, $ref, plus a depends_on cross-field check) and exposes the same { valid, errors[] } contract.

3. LLM via @mariozechner/pi-ai (injectable)

Reuse the existing stack. pi-ai is what gitclaw already uses everywhere — supports all providers, inherits telemetry and cost tracking. The llm? option makes it swappable, so tests stay offline.

4. Retry loop, not best-effort

Bounded self-healing. When the LLM emits invalid YAML, the CLI re-prompts up to 2x with the validator's errors appended; if still invalid it prints errors + the last YAML and exit(1) — no unbounded loop, no silent failure.

5. Argv dispatch, not Commander

Match the codebase. gitclaw has no Commander dep — it uses hand-rolled argv parsing with subcommand dispatch (see gitclaw plugin …). The workflow subcommand follows the same pattern.

6. Flat requires_approval, not nested compliance.*

Stay aligned with runtime. gitclaw's existing SkillFlow shape is flat (skill/prompt/channel). A nested compliance object would diverge from the loader — the flat field is what the runtime can act on today.


Proof

1. Tests pass — 24/24

Screenshot 2026-05-17 at 00 58 43

2. Typecheck clean

$ npx tsc --noEmit
$ echo $?
0

3. Pre-existing tests not regressed

Existing test/telemetry.test.ts — 8/8 still pass under the new npm test flags.

test/sdk.test.ts fails in this environment, but the failure is pre-existing and unrelated: it imports dist/exports.js, which requires npm run build against @mariozechner/* packages that aren't installed locally. Nothing in this PR touches the SDK surface.

4. End-to-end retry behavior demonstrated in tests

The "retries on invalid YAML, succeeds on second attempt" test plumbs an LlmClient that returns invalid YAML once, then valid YAML — and asserts the retry prompt to the LLM included the words "schema validation". From the test output above:

Generating workflow...
Retry 1/2 — fixing validation errors...
✔ runGenerate retries when validation fails, then writes the file when the second attempt is valid (6.11ms)

The "give up after 2 retries" test:

Generating workflow...
Retry 1/2 — fixing validation errors...
Retry 2/2 — fixing validation errors...
Workflow validation failed after retries:
  - (root): missing required property "name"
✔ runGenerate gives up after MAX_RETRIES and throws (0.50ms)

5. Schema-driven safety: example violations the validator catches

Input violation Reported error
YAML with no name (root): missing required property "name"
name: MyWorkflow (not kebab-case) name: value "MyWorkflow" does not match pattern ^[a-z0-9]+(-[a-z0-9]+)*$
steps: [] steps: array must have at least 1 item(s), got 0
Step missing prompt steps[0]: missing required property "prompt"
Step with unknown field nonsense: true steps[0]: unknown property "nonsense"
depends_on: [does_not_exist] steps[1].depends_on: references unknown step id "does_not_exist"
Truncated YAML YAML parse error: …

Issue → PR mapping (acceptance checklist)

  • Issue: "user describes the desired workflow in plain English"-p "<text>"
  • Issue: "LLM generates a complete SkillsFlow workflow with the correct nodes, order, and parameters"generateWorkflow + few-shot examples; depends_on expresses ordering
  • Issue: "User can review, edit, and save the generated workflow" — written as plain YAML to workflows/<slug>.yaml
  • Issue: "Support iterative refinement"--refine <file> mode
  • Issue (author's scope): "Component 1 — LLM prompt template (system + few-shot)"src/utils/workflow-generator.ts
  • Issue (author's scope): "Component 2 — schema validator that catches malformed output before saving"src/utils/schemas.ts + retry loop in src/commands/workflow.ts
  • Issue: "Component 3 — UI integration into the SkillsFlow builder page (Studio side)" — explicitly out of scope per the issue author

Notes for review

  • No new npm dependencies were added.
  • All new TS compiles under the existing strict tsconfig.json.
  • The default LLM client (pi-agent-core + pi-ai) is lazy-imported, so it never loads in tests.
  • OPENAI_API_KEY / <PROVIDER>_API_KEY resolution falls back through --api-key, then provider-specific env, then OPENAI_API_KEY. Missing key produces a clear error and exit(1).

…LLM integration

- Added `workflow.schema.json` for defining the structure of SkillFlow workflows.
- Created `workflow.ts` to handle the `gitclaw workflow generate` command, including parsing flags and invoking the LLM.
- Introduced `schemas.ts` for loading and validating workflows against the defined schema.
- Developed `workflow-generator.ts` to manage LLM interactions and generate workflows based on user prompts.
- Implemented tests for workflow generation and validation to ensure functionality and correctness.
- Enhanced `package.json` test script for improved testing capabilities.
@krishvsoni
Copy link
Copy Markdown
Author

Hey @shreyas-lyzr, pinging you on this one since you opened #9.

Quick heads-up on scope: per your follow-up comment on the issue, this PR ships

  • Components 1 and 2 :
    (the LLM prompt template + few-shot examples, and the schema validator with a 2-retry self-healing loop).

  • Component 3: the SkillsFlow builder UI integration on the Studio side is intentionally out of scope here, matching what you flagged as "lives in Studio."

That said, if you'd prefer to land it all in one go, I'm happy to extend this PR with:

  • a minimal chat input wired into the SkillsFlow page builder
  • a "Generate" action that calls gitclaw workflow generate (or the underlying generateWorkflow() SDK export) and renders the YAML back into the visual builder
  • the refine flow (--refine) surfaced as a follow-up prompt in the same chat

Just let me know which way you want it:

  1. Merge as-is (OSS-only scope, Studio UI tracked separately), or
  2. Extend this PR to cover the Studio UI too give me the rough shape you want
    (which page/component, where the chat lives, how the generated workflow should be applied to the canvas)
    & I'll push another commit.

Either way works for me, flagging early so we don't end up doing it twice.

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.

Feature: dynamically build SkillsFlow workflows via chat LLM

1 participant