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… Continue reading How to Script AI Agent Tasks With Codex, Gemini (agy), and Claude
The post How to Script AI Agent Tasks With Codex, Gemini (agy), and Claude appeared first on .
Summary: This is the practical playbook for scripting a task and handing it to any of three command-line (CLI) AI agents -Codex (OpenAI), agy (Gemini), and Claude (Claude Code). It covers which shell to use, how to pass the prompt, how to pass instructions and parameters, and the traps to avoid. Throughout, the running example is writing a blog post for a website, fully worked at the end. The sample commands are standalone with dummy paths - you don't need any special project files to use them.
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.
| 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
Three concrete reasons:
< 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).codex.exe exec ... < "%PROMPT%" – works.
< 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."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.for %%F, findstr, !ERRORLEVEL!). Mixing shells adds bugs, not value.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.
For find/grep/walk use rg / fd, not PowerShell loops.
One-line rule: cmd launches the AI. PowerShell configures Windows. rg/fd search files.
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).
-Cset "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."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.-, read-only):
echo Reply with exactly: PONG_CODEX | "%CODEX%" exec --skip-git-repo-check -s read-only -c model_reasoning_effort=low -
--add-dirFlag 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):
-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".agy --dangerously-skip-permissions -p "Reply exactly: PONG".-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):
--log-file showed a Windows path bug – it tried to open a Unix-style path /Users/johnsmith/.gemini/antigravity-cli/.../transcript.jsonl.--log-file to any agy run you need to debug. Spot-check the first output file it writes for real substance.--sandbox (and check your VCS status, e.g. git status / svn status, after a run).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), 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.C:\Users\<name>\…. A username change (jsmith → johnsmith) 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.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.^ at end of line; escape specials as ^|, ^<, ^>, ^&.> 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.findstr /c:"RUN_STATUS: COMPLETE" "%DIR%\...STATE.md".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.< 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.-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 †).--log-file, and use --sandbox if it must not touch anything (see Section 3).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.
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.
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.
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"
"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").C:\work\blog, so draft.md → revised.md → final.md chain works because each brief tells the agent which file to read and which to write.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).| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | How to cut AI Coding Agent Costs with Fast Local Tools | 0 | 5 | 22-06-2026 |
| 2 | AI Agents Are Wasting Your Tokens, Here’s How to Fix Long Document Pipelines | -2 | 6 | 29-06-2026 |
| 3 | Systweak Software Launches Paper: Scanner & PDF Creator for Android | 0 | 5 | 15-05-2026 |
| 4 | Identity Theft Protection – How to Prevent, Detect, and Recover From Identity Theft | 0 | 6 | 30-06-2026 |
| 5 | AI Tool of the Week: this Gemini feature tells you what matters before your workday begins | 5 | 7 | 13-06-2026 |
| 6 | Systweak PDF Editor for Android Adds PDF Compression | 2 | 6 | 13-04-2026 |
| 7 | Когда нейросети захватят мир, мы будем в первых рядах, кто ... | 7 | 6 | 26-06-2026 |
| 8 | Скучный ролик про вайб-кодинг Сделал ролик про вайбкодинг таким, каким ... | 0 | 7 | 23-06-2026 |
| 9 | Эксперт Шмидт: ИИ заменит большинство программистов в течение 2026 года | 0 | 0 | 17-04-2025 |
| 10 | Минздрав: внедрение систем с ИИ сокращает время диагностики заболеваний на 30-40% | 0 | 0 | 17-04-2025 |