How to Script AI Agent Tasks With Codex, Gemini (agy), and Claude

If you automate work with CLI AI agents, you quickly hit the same wall: each agent takes its prompt, its working directory, and its role in a slightly different way, and the wrong shell or the wrong flag order silently breaks the whole run. This guide distills the rules that actually work on Windows, learned the hard way, so you can script a task once and hand it to whichever agent you prefer.

Example user: all paths below use a fictional Windows user John Smith – short username jsmith, long username johnsmith (no spaces). Swap in your own username where you see these.


Golden rule we learned the hard way:
use cmd (.cmd batch files) to launch these CLIs, not PowerShell. The reason is stdin redirection and quoting (see Section 2).

⚠ Safety – the examples run agents unattended. They use --dangerously-bypass-approvals-and-sandbox (Codex), --dangerously-skip-permissions (agy), and --permission-mode bypassPermissions (Claude). These turn off approval prompts and sandboxing so the agent can act on its own – Codex’s own help calls this “EXTREMELY DANGEROUS.” Use them only in a folder you trust, on work under version control that you can revert, never on a shared or production machine. Drop the flag (or use Codex -s read-only / agy --sandbox) when you want a safety net.

1. The Three Clients at a Glance

Client Exe (portable form) Working dir set by Prompt in Instructions / params passed by “Done” signal
Codex (OpenAI) %LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe -C "<dir>" flag < prompt.txt (stdin) a ROLE token as one quoted positional arg state file ends RUN_STATUS: COMPLETE
agy (Gemini) %LOCALAPPDATA%\agy\bin\agy.exe pushd "<dir>" cwd, or --add-dir -p "text" arg only – no stdin (see Section 3, †) no token → uses its default role the output file it was told to write exists
Claude (Claude Code) claude (must be on PATH) pushd "<dir>" (uses cwd) < prompt.txt (stdin) command-line flags (--model, --effort, …) state file ends RUN_STATUS: COMPLETE


The same brief file can feed all three – but they read it differently.
 Codex and Claude read the prompt from stdin (< brief.txt); agy does not read stdin – you pass its prompt as the -p argument, so for a long brief you tell agy “read brief.txt and follow it” (see Section 3 †). The role is chosen differently too: Codex gets a ROLE token argument, agy uses its default, Claude is steered by flags.

Also Read: Stop AI Agents Wasting Tokens in Document Pipelines

2. Which shell – cmd vs PowerShell (the main question)

Use cmd (.cmd batch) to launch the three CLIs. Always.

Three concrete reasons:

  1. Stdin redirection < prompt.txt. Codex and Claude read the big prompt from standard input (agy is the exception – it takes its prompt as the -p argument, see Section 3).
    cmd: codex.exe exec ... < "%PROMPT%" –  works.
    • PowerShell: < is not supported (PowerShell reserves it and errors). You’d have to rewrite every call as Get-Content prompt.txt | codex.exe ..., which changes encoding/newline handling and is easy to get wrong. Not worth it.
  2. Quoting the ROLE token. Codex takes one big quoted argument like "ROLE=DRAFTER. Write the blog post described on stdin; save it as draft.md.". cmd passes it verbatim inside "...". PowerShell would re-parse =, ;, and quotes differently.
  3. The whole toolchain is already batch. Loops, resume logic, and state checks all use cmd features (for %%F, findstr, !ERRORLEVEL!). Mixing shells adds bugs, not value.

Use PowerShell only for Windows-admin tasks, not for launching the agents.

Good PowerShell jobs: editing the user PATH, environment variables, service/registry work, anything with no clean cmd equivalent. Example we actually used: adding claude’s folder to PATH with [Environment]::SetEnvironmentVariable("Path", …, "User") because setx truncates a long PATH.

Use neither for searching files.

For find/grep/walk use rg / fd, not PowerShell loops.

One-line rule: cmd launches the AI. PowerShell configures Windows. rg/fd search files.

3. Sample commands (copy-paste, dummy data)

These are self-contained – you do not need any of this repo’s .cmd files to use them. Replace the dummy values with your own:

Dummy value used below Means
C:\work\project the folder the agent should work in
C:\work\prompt.txt your prompt / instructions file (big prompts live here)
C:\work\out.jsonl , C:\work\out.err.log where stdout / stderr are saved


The exe paths use %LOCALAPPDATA% so they work for any Windows username. Run these in cmd (a .bat/.cmd file or a cmd.exe window), not PowerShell (see Section 2).

Codex (baseline / generate) – sets its own dir with -C

set "CODEX=%LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe"

"%CODEX%" exec --json --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox ^
  -c model_reasoning_effort=high -C "C:\work\project" ^
  "ROLE=BASELINE. Follow the prompt on stdin in full; keep every detail." ^
  < "C:\work\prompt.txt" > "C:\work\out.jsonl" 2> "C:\work\out.err.log"
  • exec = non-interactive run. --json = machine-readable event stream.
  • --skip-git-repo-check + --dangerously-bypass-approvals-and-sandbox = unattended, no prompts.
  • -c model_reasoning_effort=high = a config key/value (xhigh deeper, low cheap).
  • -C "C:\work\project" = Codex is the only one that takes a working-dir flag.
  • The quoted "ROLE=..." string = the instruction token, one quoted arg – this is how you steer Codex. Put a short instruction here; the bulk of the task goes in the prompt file.
  • Cheap ping (prompt read from stdin as -, read-only):
    echo Reply with exactly: PONG_CODEX | "%CODEX%" exec --skip-git-repo-check -s read-only -c model_reasoning_effort=low -

agy / Gemini – works in the current folder or --add-dir

Flag order matters: -p grabs the very next token as its prompt, so put every other flag before -p and the quoted prompt immediately after it.

set "AGY=%LOCALAPPDATA%\agy\bin\agy.exe"

REM (a) SHORT prompt - prompt is the argument to -p, all other flags first:
"%AGY%" --dangerously-skip-permissions -p "Reply exactly: PONG"

REM (b) BIG instructions - agy can't read stdin, so point it at the file instead:
pushd "C:\work\project"
"%AGY%" --dangerously-skip-permissions --log-file "agy.log" -p "Read C:\work\prompt.txt and follow it exactly." > "agy-out.log" 2>&1
popd

Do NOT write agy -p --dangerously-skip-permissions "..." (then -p eats --dangerously-skip-permissions as its prompt) or agy -p < file (fails: flag needs an argument: -p).

Verified flag list (from agy --help):

Flag Meaning
-p / --print run one prompt non-interactively – the prompt is this flag’s argument; agy never reads stdin
--prompt alias for --print
-i / --prompt-interactive run an initial prompt, then stay interactive
-c / --continue continue the most recent conversation
--conversation <id> resume a specific conversation by ID
--project <id> / --new-project pick / create a project context
--add-dir <path> add a directory to the workspace (repeatable) – the alternative to pushd
--model "<name>" pick model (list them with agy models)
--print-timeout 10m how long print mode waits (default 5m)
--log-file <path> write the CLI log (essential for debugging – see below)
--dangerously-skip-permissions auto-approve all tool actions
--sandbox run with terminal restrictions (use this to limit what it can touch)

† How the prompt is passed – this is the subtle part (verified on this install):

  • agy’s prompt is ALWAYS the -p argument. It does not read stdin. agy -p < file.txt fails with flag needs an argument: -p, and agy -p --flag "text" mis-parses (the flag becomes the prompt). Always: other flags first, then -p "your prompt".
  • Short prompt → inline: agy --dangerously-skip-permissions -p "Reply exactly: PONG".
  • Long instructions → point agy at a file: keep the -p prompt short and let agy open the file itself: -p "Read C:\work\prompt.txt and follow it exactly." This sidesteps the ~8191-char cmd argument limit and the no-stdin limitation. (Codex and Claude differ – they do take the big prompt on stdin via < file.)

⚠ Known agy issue on Windows (found 2026-07-01, confirm before trusting print output):

  • In print mode agy authenticated and sent the prompt but printed no response text. The --log-file showed a Windows path bug – it tried to open a Unix-style path /Users/johnsmith/.gemini/antigravity-cli/.../transcript.jsonl.
  • Practical rule: judge agy by the files it wrote, never by stdout. Add --log-file to any agy run you need to debug. Spot-check the first output file it writes for real substance.
  • agy is not read-only. During a bare “ping” it left a source file modified. If you don’t want it changing files, add --sandbox (and check your VCS status, e.g. git status / svn status, after a run).

Claude Code (final master) – runs in the current folder, must be on PATH

pushd "C:\work\project"

claude -p --input-format text --model opus --effort high ^
  --permission-mode bypassPermissions --output-format stream-json --verbose ^
  < "C:\work\prompt.txt" > "out.jsonl" 2> "out.err.log"

popd
  • -p = print/non-interactive. --input-format text = stdin is the plain prompt.
  • --model opus = the model. --effort max|xhigh|low. (claude --help / your model list shows valid names; some installs also accept opus[1m] for a 1-million-token context – install-specific, so use plain opus unless you know [1m] works on yours.)
  • --permission-mode bypassPermissions = no approval prompts (needed for unattended runs).
  • --output-format stream-json --verbose = full event log to the .jsonl.
  • Claude is called bare (claude), so its folder must be on PATH. If PATH is wrong you get “‘claude’ is not recognized” – the single most common breakage after a reinstall.

4. Things to keep in mind (the traps we hit)

Paths / install

  • Never hardcode C:\Users\<name>\…. A username change (jsmithjohnsmith) broke every old script. The fix is %LOCALAPPDATA% – it resolves per-user automatically, so scripts survive a reinstall or username change. Prefer that form.
  • claude must be on PATH. Add its folder (e.g. C:\Users\johnsmith\.local\bin) via PowerShell’s [Environment]::SetEnvironmentVariable(..., "User"). Do not use setx if PATH is long – it truncates at 1024 chars.
  • A PATH change only applies to new terminal windows.

Batch (cmd) syntax that matters

  • Start scripts with setlocal enabledelayedexpansion, then read changing vars as !VAR! inside loops/if blocks. Plain %VAR% is frozen at parse time and will be stale inside a for/if.
  • Line-continue with ^ at end of line; escape specials as ^|, ^<, ^>, ^&.
  • Redirection: > out (stdout), 2> err (stderr), 2>&1 (merge). All three clients log this way.
  • pushd "%DIR%"popd to run a tool “in” a folder (agy and Claude need this; Codex uses -C).
  • chcp 65001 >nul at the top forces UTF-8 (the Claude ping does this) – avoids mangled characters.
  • Check a state file with findstr /c:"RUN_STATUS: COMPLETE" "%DIR%\...STATE.md".

Running / limits

  • Exit code is the quota signal. Non-zero from any client usually means the plan limit was hit; the scripts stop cleanly and resume on re-run – they never spin.
  • Claude: run ONE instance at a time (single window). Parallel Claude burns through your plan limits faster.
  • Codex / agy can run two at once by splitting the work into odd/even slices (two windows). But one writer per state file – two Codex processes writing the same folder corrupt the state.
  • Resume signals differ: for long jobs, decide what “done” means. Codex & Claude can write a state file you grep for (e.g. ends with RUN_STATUS: COMPLETE); for agy, check that the output file it was told to write now exists. A small done.OK marker file lets a finished folder be skipped on re-run.

Prompts / instructions

  • Codex & Claude take a big prompt on stdin (< prompt.txt) – the real prompt files are tens of KB, past the ~8191-char cmd argument limit, so stdin is the only option for them.
  • agy is different: it does NOT read stdin. Its prompt is the -p argument. For big instructions, keep -p short and point agy at the file: -p "Read C:\work\prompt.txt and follow it exactly." Put all other flags before -p (see Section 3 †).
  • Pick the role by the mechanism each client uses: Codex = ROLE token arg, agy = default (no token), Claude = flags. Same task, three different “steer” mechanisms.
  • agy print mode can send but print nothing on Windows (path bug) and can edit files – verify by output files, add --log-file, and use --sandbox if it must not touch anything (see Section 3).

5. Quick smoke test before any big run (standalone pings)

Run each; a healthy client echoes the token back.

REM --- Codex: expect PONG_CODEX ---
echo Reply with exactly: PONG_CODEX | "%LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe" exec --skip-git-repo-check -s read-only -c model_reasoning_effort=low -

REM --- agy: expect PONG (flags first, then -p "prompt"; see the Windows print bug in section 3) ---
"%LOCALAPPDATA%\agy\bin\agy.exe" --dangerously-skip-permissions --new-project --print-timeout 1m --log-file "agy-ping.log" -p "Reply exactly: PONG"

REM --- Claude: expect PING_PONG_OK ---
echo Reply exactly: PING_PONG_OK and nothing else.> ping.txt
claude -p --input-format text --model opus --effort low --permission-mode bypassPermissions --output-format stream-json --verbose < ping.txt

If a ping fails: check the exe path (does %LOCALAPPDATA% resolve to your install?), check claude is on PATH, and open the .err.log / --log-file output.

6. Worked example – script a blog post (draft → revise → polish)

Goal: turn one idea into a finished blog post for your website, unattended, by chaining the three clients. Each does one stage: Codex drafts → agy revises → Claude polishes. They hand off through files in a shared folder, and each stage reads its own small instruction file.

Step 1 – write three instruction files

Put these in C:\work\blog\. Each one is a plain-text brief (the “prompt”):

1-draft.txt

Write a first-draft blog post for our company website. Topic: "Why small businesses should archive their email". Audience: non-technical small-business owners. Tone: friendly, practical. Length: ~700 words. Format: Markdown - one H1 title, 3-4 H2 sections, a short closing call-to-action. Save the result as draft.md in the current folder. Do nothing else.

2-revise.txt

Read draft.md in the current folder. Improve it: tighten the intro, add one concrete example per section, and make the call-to-action specific. Keep it ~700 words and the same Markdown structure. Save the improved version as revised.md. Do nothing else.

3-polish.txt

Read revised.md in the current folder. Do a final copy-edit: fix grammar, cut filler, ensure the H1 and headings read well, and verify the tone is friendly and clear. Save the final as final.md. Do nothing else.

Step 2 – one batch file to run the pipeline

Save as write-blog.cmd and run it from a cmd window (write-blog.cmd):

@echo off
setlocal enabledelayedexpansion
set "WORK=C:\work\blog"
set "CODEX=%LOCALAPPDATA%\Programs\OpenAI\Codex\bin\codex.exe"
set "AGY=%LOCALAPPDATA%\agy\bin\agy.exe"

echo [1/3] Codex drafting...
"%CODEX%" exec --json --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox ^
  -c model_reasoning_effort=high -C "%WORK%" ^
  "ROLE=DRAFTER. Follow the brief on stdin and write the file it names." ^
  < "%WORK%\1-draft.txt" > "%WORK%\codex.jsonl" 2> "%WORK%\codex.err.log"

echo [2/3] agy revising...
pushd "%WORK%"
"%AGY%" --dangerously-skip-permissions --log-file "agy.log" -p "Read 2-revise.txt in this folder and follow it exactly." > "agy.out.log" 2>&1
popd

echo [3/3] Claude polishing...
pushd "%WORK%"
claude -p --input-format text --model opus --effort high ^
  --permission-mode bypassPermissions --output-format stream-json --verbose ^
  < "3-polish.txt" > "claude.jsonl" 2> "claude.err.log"
popd

echo Done. Final post: %WORK%\final.md
dir /b "%WORK%\*.md"

What this shows (the three lessons in one place)

  • Same shape, three steer mechanisms: Codex is steered by the quoted "ROLE=..." token, agy by its default (no token), Claude by flags. How each gets the brief differs: Codex and Claude read it from stdin (< 1-draft.txt, < 3-polish.txt); agy can’t read stdin, so it’s told to open the file (-p "Read 2-revise.txt ... and follow it").
  • Hand-off via files: every stage runs in C:\work\blog, so draft.mdrevised.mdfinal.md chain works because each brief tells the agent which file to read and which to write.
  • You don’t need all three. Any single client can do the whole job – e.g. give Claude one brief (“write, self-edit, and save final.md”) and skip the other two. The three-stage split just gives you a draft, an independent revision, and a polish from different models.

Check the result

  • Open C:\work\blog\final.md. If a stage’s .md is missing, read that stage’s .err.log / agy.log. Remember agy may print nothing to the console – judge it by whether revised.md appeared, not by stdout (see Section 3).

Want your agents to run faster and cheaper too? Pair this scripting workflow with fast local CLI tools so your agents search and parse files instead of burning tokens – see the companion guide, How to Cut AI Coding Agent Costs with Fast Local Tools.

Frequently Asked Questions

Should I use cmd or PowerShell to launch CLI AI agents?

Use cmd (.cmd batch files) to launch Codex, agy, and Claude. PowerShell does not support the

How do Codex, agy, and Claude each receive their prompt?

Codex and Claude read the prompt from standard input (

How do I set the agent's role for each client?

Each client uses a different mechanism. Codex takes a quoted ROLE token as a positional argument. agy has no token and uses its default role. Claude is steered by command-line flags such as --model and --effort.

Why should I never hardcode C:Users<name> paths?

A username change breaks every hardcoded path. Use %LOCALAPPDATA% instead - it resolves per-user automatically, so scripts survive a reinstall or a username change.

Is it safe to run these agents unattended?

The unattended examples turn off approval prompts and sandboxing (Codex calls this 'EXTREMELY DANGEROUS'). Only use them in a folder you trust, on work under version control you can revert, never on a shared or production machine. Drop the bypass flag or use a read-only/sandbox mode when you want a safety net.

Shrishail Rana: