Skip to content

Vibe coding with AI agents

"Vibe coding" here means using an AI coding agent (Claude Code, Cursor, Aider, GitHub Copilot, …) to author workflows in athena-sdk-lite by describing what you want in natural language, then letting the agent generate the Python.

This only works if the agent knows the SDK's conventions: the canonical import pattern, the 11 helpers and their kwargs, how branch conditions are written, what transform code looks like, what NOT to do. That's what AGENTS.md is — a context file the agent reads first, every time, so it doesn't have to guess.


The pattern in 3 steps

1. Point your agent at AGENTS.md

Agent How
Claude Code Auto-discovers AGENTS.md at the repo root. No setup.
Cursor Auto-discovers AGENTS.md (also reads .cursor/rules/*.mdc).
Aider aider --read AGENTS.md
Copilot Add AGENTS.md to the chat context, or paste the relevant section before each prompt.
Anything else Open AGENTS.md, copy contents, paste as the first system/user message.

The file lives at the repo root (athena-sdk-lite/AGENTS.md) because that's where coding agents look by convention. The same content is mirrored at docs/AGENTS.md so MkDocs can serve it; keep the two in sync if you edit.

2. Describe the workflow you want

Plain English, focused on business intent, not Python syntax:

Build a workflow that pulls active orders from Postgres, flags high-value ones (>$1000) using a custom transform, sends them to our fraud-detection agent, branches on fraud_score > 0.7, and writes alerts and the routine queue into two different output sinks.

A well-briefed agent reading AGENTS.md will produce something close to the worked example in Building a workflow on the first try.

3. Validate before you trust

print(wf.visualize())
issues = wf.validate()
assert issues == [], issues

An agent can write code that parses but doesn't validate (missing upstream, broken branch wiring, unsupported kwarg). The validator catches these structurally before you run anything. Add it to your pre-commit hook so generated workflows can't sneak into main.

What's in AGENTS.md

The file is structured for fast LLM scanning, not human reading. It covers:

  • The single canonical import pattern (function-first, never method-first for new code)
  • All 11 helpers with required kwargs and a one-line "notes" column
  • How to wire nodes (inputs=, fan-out, fan-in, branch ports)
  • Branch condition syntax ($input.data.get(...))
  • transform code shape (inputs["data"] row stream, return same shape)
  • Variables and {{ name }} templating
  • Anti-patterns the agent must NOT generate (no internal URLs, no inlined creds, no _engine.* imports, no mixing styles)
  • File layout convention (workflows/<name>.py)

Open AGENTS.md to read the current version.

A sample prompt

Once your agent has the AGENTS.md context, prompts can be short and intent-focused:

Build me a workflow workflows/adverse_event_triage.py that:

  1. Pulls the last 24 hours of adverse_events from Postgres where triage_status IS NULL
  2. Runs custom Python to compute days_since_onset and flag rows where narrative contains any of {death, hospitalized, anaphylaxis, seizure, stroke}
  3. Sends each row to the AE-classification agent at {{ agent_url }} and gets back a severity classification
  4. Branches: if classification is in (serious, life_threatening) OR rows have missing critical fields → build an SAE alert payload and insert into sae_escalations; otherwise → minimal projection inserted into triage_queue

Use the variables agent_url and db_password (already set externally). Do not hardcode any URLs.

The agent should produce something equivalent to examples/11_triage_pipeline.py.

Reviewing what the agent wrote

Things to check before accepting agent-generated code:

Check How
Imports from athena_sdk_lite.nodes Top of file uses from athena_sdk_lite.nodes import ...
Body wrapped in with Workflow(...) as wf: Single with block, no module-level wf = Workflow(...)
No real internal hostnames or credentials grep for aviradigital, aviralabs, internal, passwords
Branch conditions use $input.data.get(...) Not raw Python; not row["key"] direct access
Transforms return {"data": [...]} Same shape they receive; not a bare list
wf.validate() returns [] Run the file; check the printed validation result
Validates in a subprocess (clean state) python workflows/your_file.py exits 0

If you have tests/test_examples_validate.py-style infrastructure, drop the generated file into workflows/ and let CI run it.

Things AGENTS.md will NOT fix

The agent still hallucinates occasionally. Common failure modes:

  • Inventing a helper that doesn't exist. The 11 helpers in AGENTS.md are the full set (plus the wf.add_node escape hatch). If the agent writes wf.snowflake(...), it's wrong.
  • Mixing method-first and function-first. AGENTS.md forbids this for new code, but agents sometimes regress to method-first. Look for wf.pubmed(...) etc. and rewrite.
  • Hallucinating engine node types in wf.add_node. The valid types are whatever the vendored engine supports; check src/athena_sdk_lite/_engine/ if a generated type= looks suspicious.
  • Inventing branch condition syntax. The valid form is $input.data.<expr>. Anything else (e.g. row.score > 0.8) is wrong.

When you spot a recurring failure mode, add an explicit "do not" line to AGENTS.md and the agent will stop doing it next time.

CI gate for vibe-coded workflows

If you're letting agents author workflows on a regular basis, make this a pre-commit hook:

# .git/hooks/pre-commit  (or use pre-commit framework)
python -c "
import sys, importlib.util
from pathlib import Path

failed = []
for f in Path('workflows').glob('*.py'):
    spec = importlib.util.spec_from_file_location(f.stem, f)
    mod = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(mod)
    if hasattr(mod, 'wf'):
        issues = mod.wf.validate()
        if issues:
            failed.append((str(f), issues))

if failed:
    for f, issues in failed:
        print(f'❌ {f}: {issues}')
    sys.exit(1)
print('✅ all workflows validate')
"

If a generated workflow doesn't validate, the commit is rejected. Cheap, prevents drift, gives you confidence that agent-authored code didn't sneak structural bugs into your repo.

Next