Cron for repositories and coding agents. Jobs live in the repo, run on your machine or in a container, leave history you can inspect, and never run unattended until you say so.
![]() Browse jobs, runs, and logs in the TUI |
![]() Queue a job, follow its log, find the failure |
# noon.yaml
version: 1
timezone: America/Denver
jobs:
tests:
schedule: every day at 2am
run: [go, test, ./...] # list: exact argv
deps:
schedule: "0 6 * * 1"
run: ./scripts/check-deps # string: /bin/sh -c
env_file: .env # gitignored, read at each run
timeout: 10m
review:
schedule: weekdays at 9am
jitter: 15m # start between 09:00 and 09:15
agent: claude
prompt: Review open PRs and list risks.macOS or Linux, amd64 or arm64:
brew install brettinternet/tap/noon # Homebrew
mise use -g github:brettinternet/noon@latest # or mise (pin with @0.1.0)
mise trust && mise exec -- task init && task cli:build # or from source → bin/noonIf mise's minimum-release-age policy hides a new release from latest, pin the version.
Installing never starts a scheduler. Start one explicitly, and re-run install after each upgrade:
noon service install # per-user launchd/systemd service; reconciles upgrades
noon serve # or run in the foregroundRestarts interrupt active jobs. Config edits and env_file changes need no restart. See
upgrades and migration.
noon add writes to the private .git/noon.yaml, which Git can't commit. --shared writes
noon.yaml instead.
$ noon add tests "every day at 2am" -- go test ./...
Added tests to .git/noon.yaml (private) · every day at 02:00 · next Sat 02:00
Scheduling enabled for /home/me/app.
The scheduler isn't running, so nothing runs in the background.
Suggested action: noon service install · noon run tests
$ noon run tests
▶ tests · run 1 · "go" "test" "./..."
ok example.com/app 0.412s
✓ tests succeeded in 1.2s
$ noon
app · /home/me/app · scheduler offline · America/Denver
JOB SCHEDULE NEXT LAST
tests every day at 02:00 Sat 02:00 ✓ now (1s)
Scheduler offline; background work will wait.
Suggested action: noon service installBare noon shows the project and one suggested next step. It never starts anything.
Cloning or pulling a repository can't schedule commands on your machine:
$ git clone https://example.com/team/app && cd app
$ noon
app · /home/me/app · scheduler offline · Local
JOB SCHEDULE NEXT LAST
lint every 6h needs approval never
Not enabled for background runs.
Suggested action: noon enable
$ noon enable
Enabled /home/me/app · 1 jobs · approved 1 shared jobs| Job source | Background runs need |
|---|---|
noon.yaml (shared) |
noon enable, again after a pull changes the job |
.git/noon.yaml (private) |
noon enable once; no approval |
noon add --temporary (private state) |
creation enables the project; no approval |
noon run NAME (foreground) |
nothing |
noon disable revokes everything and keeps history. Approval covers job definitions, not the
scripts or prompt files they reference, so only enable repositories you would run by hand. Noon
ignores an in-tree .noon.yaml, since a commit could supply it.
For bounded follow-ups without editing config (including symlinked private config):
noon add watch-pr-42 "every 2h" --temporary --for 3d --agent claude --prompt "Check PR 42 CI; fix failures" --key pr-42
noon cancel watch-pr-42 # end now; visible for 24h, then removedTemporary jobs end within 7 days. noon remove NAME deletes the definition immediately;
run history remains. Only the CLI creates them, not MCP or the HTTP API.
--user selects jobs that belong to no repository. They live in ~/.config/noon/config.yaml
(honoring $XDG_CONFIG_HOME), run from that directory, and need no approval:
noon --user add disk-space "every day at 9am" -- ./bin/disk-space.sh
noon --user list
noon --user run disk-spaceThe service runs them with every other enabled project. See user project and examples/local-dev/housekeeping.
| Command | What it does |
|---|---|
noon / noon status |
Dashboard: jobs, scheduler, queued work, next step |
noon list |
Jobs and next run times |
noon add NAME [SCHEDULE] -- CMD… |
Add a job (--sh, --prompt, --prompt-file, --shared); --temporary --for 2h keeps it in state, not config |
noon remove NAME... |
Remove job definitions; history stays |
noon run NAME |
Run now; returns 0 when noop_exit_code matches |
noon run NAME... --detach |
Queue jobs for the scheduler (--in 2h, --at 17:00, --key, --data); --schedule S --for 2h repeats approved jobs |
noon cancel RUN|NAME... |
Cancel selected runs or end temporary jobs/schedules and their active work |
noon pause NAME... / resume NAME... |
Stop or restart background runs; -a for all jobs, --for/--until to resume automatically, --from to schedule the window |
noon history [NAME...] |
Recent runs (--status failed) |
noon logs [NAME|RUN] |
Read, search, page, or --follow a run log (-t for timestamps) |
noon enable / disable |
Opt this checkout in or out of background runs |
noon serve |
Foreground scheduler; optional webhooks and remote API/MCP |
noon service install / restart |
Per-user launchd/systemd service; restart interrupts jobs |
noon doctor |
Read-only setup checks |
noon tui / ui |
Keyboard-driven jobs, runs, and logs (? for keys) |
noon mcp |
MCP tools over stdio for coding agents |
noon import crontab FILE |
Preview a crontab as Noon YAML; --write to add it |
noon shell init bash |
Shell completion; optional job on cd |
noon init / config |
Create noon.yaml; show or check settings |
noon version |
Version, commit, and build time |
Finishing commands accept -j / --json. NO_COLOR=1 or --color=never disables styling.
Commands that need a target list candidates or print examples instead of guessing:
$ noon add
Examples:
noon add tests "every day at 2am" -- go test ./...
noon add lint "every 30m" --sh 'golangci-lint run ./...'
noon add review "weekdays at 9am" --agent claude --prompt "Review open PRs and list risks"
noon add notes --agent claude --prompt-file prompts/notes.md
noon add check-ci --in 2h --agent claude --prompt "Check CI and fix failures"$ noon history --status failed
RUN JOB STATUS TRIGGER STARTED DURATION EXIT
7 check failed schedule 2h ago 3s 3
$ noon logs check --status failed --match FAIL --context 1 --timestamps
2026-10-19T09:15:30.125-06:00 2-ok 2
2026-10-19T09:15:30.125-06:00 3:FAIL widget
2026-10-19T09:15:30.126-06:00 4-ok 3
Continue: noon logs 7 --after-cursor 27 --timestampsWith MCP, a coding agent can list jobs, queue approved ones, attach a temporary schedule ending within 7 days, and read logs. It can't add, edit, enable, or approve jobs.
claude mcp add noon -- noon mcp
codex mcp add noon -- noon mcpPrompt jobs have built-in profiles for claude, codex, gemini, opencode, and pi; install
and authenticate the CLI yourself. See Agents for remote MCP and prompt jobs.
- Examples: runnable projects for local dev, AI workflows, and integrations
- Command reference: output, exit codes, queueing, history, logs, TUI
- Configuration: files, precedence, job fields, agent profiles, editor schema
- Agents: MCP, agent-facing jobs, reading failures
- Lifecycle hooks: notify on failure and recovery
- Triggers: Git hooks, Claude Code and Codex
Stophooks - Webhooks: signed GitHub webhooks and the remote API listener
- Shell setup: completion and project-entry jobs
- Crontab import
- Service: launchd and systemd
- Docker
- Design: contracts and rationale
- Changelog: changes generated from Conventional Commits
- Development


