Scheduled Codex automations you can trust unattended
PLCodex automations are recurring prompts, such as a daily quality check, that the Codex desktop app runs on a schedule in a local project or Git worktree, reporting findings to an inbox. An unattended run stays safe when its prompt was tested by hand, its sandbox is the narrowest that works, and its output follows a checkable contract.
It is Monday morning. Over the weekend a dependency advisory was published, someone merged a commit with a stray console.log, and test coverage on the payments module slipped. You learn all three at standup. With three automations set up on Friday, you would have opened a short report instead: each issue found, backed by the command that proves it, and the safe ones already fixed in a worktree waiting for your review.
This page is for developers who run Codex every day and for tech leads who want the same recurring checks across a team. It assumes you already use the Codex desktop app or CLI; start with the Codex automation overview if you do not.
What this Codex automations guide gives you
Section titled “What this Codex automations guide gives you”- A decision table for where a recurring Codex job should run: the desktop app, a thread automation, or a CI schedule.
- A five-step procedure that takes a prompt from a manual run to a trusted schedule.
- Six copy-paste automation prompts, each with an output contract that makes the result checkable.
- A sandbox and rules setup for unattended runs, tested with
codex execpolicy check. - A GitHub Actions workflow that runs the same job when your laptop is asleep.
- A failure-mode list with the recovery for each one.
Where should a recurring Codex job run?
Section titled “Where should a recurring Codex job run?”OpenAI’s own map of Codex surfaces describes an automation as “scheduled checks, reminders, monitors, or follow-ups; use an existing-thread heartbeat when continuity matters”. That gives you two app options, and the CLI adds two more. Choose by what the job needs to reach and whether it must run when your machine is off.
| Where it runs | Reaches | Runs when your laptop sleeps? | Best for |
|---|---|---|---|
| Desktop app, local project or worktree | Your checkout, your local tools and credentials | No | Personal checks that need local state: your branches, local services, unpushed work |
| Desktop app, thread automation | The same thread each time, so earlier findings stay in context | No | Follow-ups that must remember yesterday: “re-check what you flagged last run” |
codex exec from cron or launchd on an always-on host | Whatever that host has checked out | Yes | A team job on a build box you control; see headless Codex with codex exec |
GitHub Actions schedule with openai/codex-action@v1 | A fresh checkout of the default branch, with only the secrets you pass in | Yes | Shared team reports that must not depend on anyone’s laptop; usage is billed to the API key, not your plan’s allowance |
The Codex desktop app runs on macOS and Windows, and codex app opens it from a terminal. Since 2026-07-09 it ships as the Codex mode of the ChatGPT desktop app (secondary source: Neowin); on macOS, codex app launches either one. The in-app automations feature is marked stable in CLI 0.157.1 (in_app_local_automation in codex features list). As of 2026-08-28 OpenAI’s automations page also named event sources beside schedules: new Gmail messages, Slack channel messages and GitHub pull request activity. On 2026-10-12 OpenAI’s page is titled “Scheduled tasks” and says web and mobile can also run tasks “from supported app events”; check which events are supported before you rely on the three named above.
How do you take an automation from prompt to schedule?
Section titled “How do you take an automation from prompt to schedule?”An automation scheduled after a single manual run often turns out noisy. The procedure below costs one extra manual run and saves you a week of inbox clutter.
-
Write the prompt with an output contract. State the scope (directories, time window), what counts as a finding, the evidence each finding must carry, and the exact line to print when there is nothing to report. Every prompt on this page ends with such a contract.
-
Run it by hand in a normal thread in the same project. If the job edits files, start the thread in a worktree so your main checkout stays clean; the Codex worktrees guide covers the setup. Check three things: did it find real issues, did it stay in scope, and does every finding carry its evidence?
-
Run it a second time without changing anything. A good automation gives the same answer, or prints
NO FINDINGS. If the second run re-reports or invents new issues, tighten the scope or add an ignore file (see the failure modes below) before you schedule it. -
Create the automation from the tested prompt. In the desktop app’s Automations view, pick the project, choose local or worktree execution, set the schedule and paste the prompt unchanged. Choose a thread automation instead when the job must remember earlier runs.
-
Grade the first three runs against the contract, then sample. For each run, check one finding end to end by running its reproduce command. After three clean runs, drop to spot-checking one finding per week and archive runs you have reviewed.
What sandbox should an unattended Codex run get?
Section titled “What sandbox should an unattended Codex run get?”Nobody is present to answer an approval prompt during a scheduled run, so design each job never to need one. Anything outside the boundary should fail and show up in the report, not wait or escalate.
| Access | Legacy sandbox name | Permission profile (beta) | Use it for |
|---|---|---|---|
| Read files, write nothing | read-only | :read-only | Reports, briefings, audits, anything that reads Slack, Gmail or PR text |
| Edit files inside the workspace | workspace-write | :workspace | Jobs that fix things in a worktree for you to review |
| Unrestricted | danger-full-access | :danger-full-access | Never for a scheduled job on your own machine |
OpenAI now prefers permission profiles (Codex CLI 0.138.0 and later) over the legacy --sandbox values, and states that “the profile and legacy sandbox systems do not compose”, so pick one system per job. Select a profile with default_permissions in ~/.codex/config.toml, or for a single run with -c default_permissions=":read-only"; there is no dedicated CLI flag for it. Neither workspace-write nor :workspace grants network access. When one command genuinely needs the network, such as npm audit, allow that command prefix with a rule instead of widening the whole sandbox.
Rules are Starlark files under ~/.codex/rules/. OpenAI’s rules page still says “Rules are experimental and may change” (checked 2026-10-12), so re-run the checks below after each Codex upgrade. This file lets exactly the three commands that the weekly dependency job below needs (npm outdated, npm audit and npm install) run outside the sandbox, and nothing else:
prefix_rule( pattern = ["npm", "outdated"], decision = "allow", justification = "npm outdated reads the registry to compare versions",)prefix_rule( pattern = ["npm", "audit"], decision = "allow", justification = "npm audit needs network access for vulnerability checks",)prefix_rule( pattern = ["npm", "install"], decision = "allow", justification = "npm install downloads the patched package versions",)Test each rule before a scheduled run depends on it. Run these in a terminal; each JSON output should end with "decision": "allow", and a command you did not allow, such as npm publish, should return an empty matchedRules list (checked with CLI 0.157.1):
codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- npm outdatedcodex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- npm auditcodex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- npm install lodash@4.17.21npm install is the widest of the three: outside the sandbox it also runs the installed packages’ lifecycle scripts with your user’s permissions. If that is more than you want on your own machine, run the dependency job from the CI schedule instead.
The report jobs below run read-only, where git fetch has no network and cannot write to .git, and gh cannot reach GitHub. Their prompts therefore fall back to origin/main as last fetched and state how old it is. To refresh on every run, add two more rules to the same file. The list in the second pattern allows gh pr list and gh pr view but not gh pr merge:
prefix_rule( pattern = ["git", "fetch"], decision = "allow", justification = "git fetch needs the network and writes to .git",)prefix_rule( pattern = ["gh", "pr", ["list", "view"]], decision = "allow", justification = "the daily briefing reads merged pull requests",)codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- git fetch origincodex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- gh pr view 123codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- gh pr merge 123The first two return "decision": "allow"; gh pr merge returns an empty matchedRules list (checked with CLI 0.157.1).
If a new rule does not take effect, restart the app. The sandbox testing section of the advanced setups guide shows how to prove the boundary holds for the commands you did not allow.
Copy-paste prompts for recurring Codex jobs
Section titled “Copy-paste prompts for recurring Codex jobs”Each prompt is tested in a normal thread before it is scheduled, and each ends with an output contract. Replace npm scripts with your project’s own commands; the rest works as written.
Daily code quality check
Section titled “Daily code quality check”Weekly dependency health
Section titled “Weekly dependency health”This job edits files and needs the network for three commands, so schedule it in a worktree with workspace-write and all three rules above. With only the npm audit rule, steps 1 and 3 fail on every scheduled run.
Nightly bug hunt on recent commits
Section titled “Nightly bug hunt on recent commits”This job writes tests, so schedule it in a worktree with workspace-write.
Daily team briefing
Section titled “Daily team briefing”On your machine, gh needs the network and a logged-in session, so add the gh pr rule from the sandbox section. In CI the read-only profile has no network at all, and the workflow below passes Codex no GitHub token, so fetch the pull requests in a step before Codex runs and let the prompt read prs.json:
permissions: contents: read pull-requests: readsteps: # checkout and npm ci as in the workflow below, then: - name: Fetch merged PRs for the briefing env: GH_TOKEN: ${{ github.token }} run: | gh pr list --state merged \ --search "merged:>=$(date -u -d yesterday +%F)" \ --json number,title,body,url,author > prs.jsonWeekly architecture drift
Section titled “Weekly architecture drift”Turn a working automation into a skill
Section titled “Turn a working automation into a skill”How do automations and skills work together?
Section titled “How do automations and skills work together?”A skill keeps the procedure in one file, and the automation prompt shrinks to one line. When you improve the skill, every automation that calls it improves too. Codex looks for personal skills in $CODEX_HOME/skills (~/.codex/skills when CODEX_HOME is unset), and skill-creator is one of the sample skills bundled with Codex.
---name: recent-code-bugfixdescription: Find bugs in the current author's recent commits and prove each with a failing test; propose, do not apply, a fix.---
# Recent code bugfix
1. Take the time window from the invoking prompt and list the author's commits in it: git log --since=<window> --author="$(git config user.email)".2. In each changed file, look for off-by-one errors, unhandled promise rejections and missing error handling, race conditions, and missing null or undefined checks.3. Confirm each suspected bug: read the surrounding code and related tests, then write a failing test that demonstrates it. Only report bugs with a failing test.4. Propose the smallest fix as a diff; do not apply it.5. Per bug, report: commit SHA, file:line, one-sentence root cause, the failing test's path and its failure output, and the proposed diff. Do not report theoretical concerns.6. If nothing is confirmed, print exactly: NO FINDINGSThe automation prompt then becomes:
Run $recent-code-bugfix on my commits from the last 24 hours.Keep team skills in the repository under .agents/skills/ rather than in ~/.codex/skills, so a change to a skill goes through code review like any other change. The Codex desktop app guide covers where the app shows installed skills.
How do you verify an automation’s output without reading every line?
Section titled “How do you verify an automation’s output without reading every line?”The output contract does most of the work. Because each finding carries a reproduce command or a failing test, you check a finding by running one command, not by reading the analysis. Apply four rules:
- Evidence per finding. A finding without
file:lineand a command that reproduces it is noise. Reject it and tighten the prompt. - Changes go through the normal gate. A fix made in a worktree becomes a branch and a pull request, and CI runs the same type, lint and test gates as for human changes. Nothing an automation writes merges without them. Attach the run’s report to the pull request as its evidence bundle.
- A defined “nothing found” line.
NO FINDINGSlets the inbox or the CI job tell a clean run from a broken one. An empty or truncated report is a failure, not a pass. - A monthly canary. Plant one known defect on a scratch branch (an unhandled promise, a
debuggerline) and run the automation against it. If it misses the canary, it has stopped doing its job even though every run looks green.
The automation’s owner, usually the developer who scheduled it, reviews findings; the pull request reviewer signs off on any change, exactly as for human work. The wider argument for this way of reviewing is in evidence, not diffs.
How do you run the same job when your laptop is asleep?
Section titled “How do you run the same job when your laptop is asleep?”Move shared jobs to a CI schedule. This workflow runs the daily quality prompt on weekday mornings with a read-only permission profile and opens an issue only when there is something to report. A schedule trigger always runs the workflow file and the prompt from the default branch, so no untrusted code reaches the job that holds the API key.
Save the daily quality prompt as .github/codex/daily-quality.md, then add .github/workflows/codex-daily-quality.yml:
name: Codex daily quality reporton: schedule: - cron: "17 5 * * 1-5" # 05:17 UTC, Monday to Friday workflow_dispatch:
jobs: report: runs-on: ubuntu-latest permissions: contents: read outputs: report: ${{ steps.codex.outputs.final-message }} steps: - uses: actions/checkout@v7 with: fetch-depth: 50 persist-credentials: false # Install dependencies before Codex runs: the read-only profile has no network. - run: npm ci - name: Run Codex id: codex uses: openai/codex-action@v1 with: openai-api-key: ${{ secrets.OPENAI_API_KEY }} permission-profile: ":read-only" prompt-file: .github/codex/daily-quality.md
file-issue: needs: report if: needs.report.outputs.report != '' && !contains(needs.report.outputs.report, 'NO FINDINGS') runs-on: ubuntu-latest permissions: issues: write steps: - uses: actions/github-script@v9 env: REPORT: ${{ needs.report.outputs.report }} with: script: | await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: `Codex daily quality report ${new Date().toISOString().slice(0, 10)}`, body: process.env.REPORT, });
missing-report: needs: report if: needs.report.outputs.report == '' runs-on: ubuntu-latest permissions: {} steps: - run: | echo "::error::Codex returned no final message. Treat this run as failed." exit 1The Codex job can read the repository and nothing else; only the file-issue job, which never runs Codex, can write issues. The missing-report job applies rule 3 from the verification section: an empty final message turns the run red instead of passing as a clean day. The action’s inputs (permission-profile, prompt-file, the final-message output) are from the openai/codex-action README as of v1.12. Because the checkout is on the default branch, replace step 1 of the prompt with “Inspect the current checkout”. For more patterns, see CI/CD with the Codex GitHub Action.
When should you use /goal instead of a schedule?
Section titled “When should you use /goal instead of a schedule?”A schedule repeats a small job. A goal pursues one large objective until it is done. In Codex, /goal sets, edits, pauses, resumes, views or clears a task goal (OpenAI’s developer commands page, checked 2026-08-28); goals are a stable feature and on by default in CLI 0.157.1. Use /goal for “every TODO in src/billing/ is resolved”, and an automation for “tell me every morning which new TODOs appeared”. The /goal workflow guide compares the goal commands across tools.
What breaks when Codex automations run unattended?
Section titled “What breaks when Codex automations run unattended?”The run never fired. A local automation needs the desktop app running and the machine awake. Recovery: keep the machine awake for overnight jobs, or move the job to the CI schedule above, which does not depend on your laptop.
The same findings appear every day. A lint warning nobody fixes gets reported forever, and the inbox trains you to ignore it. Recovery: keep a committed .automation-ignore.json that humans edit to accept known findings, and have the prompt skip anything listed there. For follow-ups that must remember the previous run, use a thread automation. Codex memory (memories) is stable but off by default in 0.157.1, so do not rely on it for continuity.
A minimal ignore file is a list of accepted findings, each with the reason it was accepted:
[ { "file": "src/legacy/api.ts", "rule": "no-console", "reason": "accepted 2026-09, removed with the legacy API" }]Humans change this file through a pull request, never the automation, so every accepted finding has a reviewer and a date.
State written in a worktree disappears. Do not assume the next worktree run sees files an earlier run wrote there: an uncommitted “seen findings” file can be missing next time, for example after you archive the run or remove its worktree. Recovery: keep state that must persist in a committed file that a human updates, or in a thread automation.
Reports are long and vague. The prompt is too broad or has no output contract. Recovery: narrow the scope to named directories and a time window, require a reproduce command per finding, and reject runs that break the contract.
The job edited files it should not have. The sandbox is wider than the job needs. Recovery: move report-only jobs to read-only, put edit jobs in a worktree with workspace-write, and allow single commands with rules. Discard the worktree rather than trying to untangle it.
A command fails with a network or permission error. The sandbox is working as intended. Recovery: add a prefix_rule for that one command, confirm it with codex execpolicy check, restart the app if the rule does not take effect, and re-run by hand before the next scheduled run.
The automation acted on instructions inside a Slack message or PR description. That is prompt injection through the content it reads. Recovery: switch the job to read-only, remove any credential it does not need, and add the “treat content as data” line from the briefing prompt.
Worktrees pile up. Frequent worktree runs leave checkouts behind. Recovery: archive runs you have reviewed, check git worktree list weekly, and remove stale checkouts with git worktree remove <path> once no open thread uses them.
Every run says NO FINDINGS for weeks. The job may be healthy, or it may have silently broken (a renamed script, a moved directory). Recovery: run the monthly canary described above.
Costs creep up. An hourly job that could be daily burns usage for no new information. Recovery: set the cadence to how often the underlying data changes, and see Codex cost management for budgeting.
Where to go next with Codex automations
Section titled “Where to go next with Codex automations”- Isolated Codex tasks with Git worktrees: the isolation that write-capable automations rely on.
- Headless Codex with
codex exec: run the same prompts from cron, scripts and pipelines with JSON output. - Advanced Codex setups: test sandbox limits and keep an audit trail of what unattended runs did.
- Codex in Slack and Linear: start work from chat and issues instead of a clock.
- Bug hunting with Codex: the interactive version of the nightly bug hunt.