Everything that runs without you watching, and everything that gets into and out of Camy without a chat turn.
| Area | Start with | What it is |
|---|---|---|
| Jobs | camy jobs |
durable, multi-day work |
| Schedules | camy schedule |
one instruction on a timer |
| Runs | camy runs search |
what your agents did, and what they said |
| Tasks | camy tasks |
quick to-dos; nothing fires on its own |
| Capture | camy capture |
one line into memory intake |
| Integrations | camy integrations |
connected accounts |
| Webhooks | camy webhooks |
endpoints and their deliveries |
A job is a durable, multi-day piece of work — the kind that keeps firing over days, as opposed to a schedule, which fires one instruction on a timer. Jobs are created elsewhere, in a chat or by an agent; this area lists, searches, inspects, cancels, and nudges them.
camy jobs
camy jobs --status active --limit 20
camy jobs --all --jsonPrints a list under a count of how many jobs are live and how many need
you: a short id such as jb_3f2a, the job's title, its state, and next
fire. A job in a terminal state — cancelled, failed, expired, disabled,
done, or completed — always shows — for next fire, even if the server
still has a stale timestamp on the row, since a terminal job fires never.
| Flag | Effect |
|---|---|
--status string |
one of active, suspended, blocked, completed, failed, cancelled, needs_attention, passed straight through and not validated locally |
-L, --limit int, --offset int |
page manually; --limit takes 1 to 100 (default 100), and anything else is a usage error before any network call |
--all |
auto-paginate to the end |
If a page fails partway through an --all sweep, the rows already fetched
are kept, not thrown away. Human mode prints them plus a note that it
stopped early, and --json mode emits
{"partial": true, "results": [...], "rows": N, "error": "..."}. Both
still exit non-zero.
camy jobs search "newsletter"
camy jobs search "invoice" --status active
camy jobs search "invoice" --offset 25Finds jobs by the words you set them up with and prints them in the same
list as camy jobs, under a count of how many matched. When the page
comes back full, a line under the list says more may match and names the
flag for the next page:
more jobs may match than this page shows — --offset 25 for the next page
A page past the last match says
no more jobs matched "invoice" past offset 25 rather than that nothing
matched. QUERY... is one or more words, joined with spaces, up to 200
characters.
| Flag | Effect |
|---|---|
--status string |
the same values as camy jobs --status, passed straight through; a value the server doesn't know finds nothing rather than failing |
-L, --limit int |
how many to show, 1 to 100 (default 25) |
--offset int |
skip that many matches (default 0); a negative value is a usage error before any network call |
If search isn't on for your account yet, the command says so and exits 1.
camy jobs show jb_3f2a
camy jobs show jb_3f2a jb_02e2
camy jobs show jb_3f2a --webShows one job as a pane. What it's stuck on comes first, if anything: a
question nobody answered, with the camy approvals answer command that
frees it, or the error from its last run. Then its title, schedule and next
fire, last run, how its runs went, and, when the job has them, its
progress, credits spent (fractions included, as in 12.5 spent), and the
chat it came from. The pane shows up to eight recent runs, newest first.
--json carries up to the 50 most recent runs; older runs aren't
returned. Name several ids to get a pane each.
--web opens camy.ai instead of rendering the job: it prints the link to
Settings → Activity, where your jobs are listed (there's no page for a
single job), and opens it in your browser. It takes one id. The link prints
on stdout even under --json, so don't combine --web with --json in a
script.
With --web the id is still checked against your job list, so a ref
under 4 characters or one matching several jobs fails in the terminal. An
id that matches no job is not caught, and the Activity page opens anyway.
A short id costs one list call; a full id skips the network.
ID is the short id the list prints (jb_3f2a), a prefix of at least 4
characters, or a full id. A short id is resolved against the job list; one
matching more than one job is a usage error. It is matched against the
first 100 jobs only; for a job older than that, pass the full id.
camy jobs cancel jb_3f2a
camy jobs run-now jb_3f2acancel stops the job and its schedule, and asks for confirmation first
(see Destructive confirmations). It takes
several ids and asks once for all of them. run-now
pulls the job's next fire forward to now, but isn't synchronous: it fires
on the dispatcher's next tick, about 30 seconds out.
See camy jobs, camy jobs search, camy jobs show, camy jobs cancel, and camy jobs run-now for the full flag list.
camy scheduleLists everything that fires on a timer: the scheduled tasks you made
with schedule create (an agent can make one for you in a chat, too), the
reminders and timers an agent set for you during a chat, and any other
schedules on your account. These live in separate places behind the
scenes, and camy schedule merges them into one list, soonest next fire
first. Each row has a mark (● when it fires, ○ when it's paused), a
short id such as sc_3f2a, what it fires, when (daily, hourly,
weekly, once, the kind of reminder or timer, or a cron), and its next
fire.
A recurring schedule shows its next fire, not the first one it ever had.
A paused schedule stays in the list, under the same id, with — for next
fire, since it won't fire until you resume it; it sorts after everything
that will. The schedule behind a suspended job rests the same way, marked
○ with — for next fire. A scheduled task on a cron outside the three
WHEN shapes below (weekdays only, say) shows the cron itself and — for
next fire.
The reminders-and-timers half of the list covers the first 100 that are
still pending (active, paused, or snoozed), soonest fire first. When all
100 come back, the count above the list reads N+ schedules and a line
under it says more are active than shown. If reading those, or your
scheduled tasks, fails, the list quietly leaves them out.
camy schedule create WHEN --run INSTRUCTION [--tz ZONE] [--channels LIST] [--dry-run]Creates a scheduled task. Each time it fires, Camy carries out the
instruction on its own, with web search as its one tool, and delivers a
short report to the channels in --channels.
WHEN accepts exactly three shapes:
| You write | Means | Cron |
|---|---|---|
"07:00" |
daily at that time; the first fire is tomorrow if it's already past today | 0 7 * * * |
"hourly" |
the next hour boundary, then every hour after | 0 * * * * |
"mon 07:00" |
weekly, that weekday and time (sun…sat, first 3 letters, case-insensitive) |
0 7 * * 1 |
camy schedule create "07:00" --run "prep my morning brief"
camy schedule create "mon 09:00" --run "weekly pipeline review" --tz America/ChicagoWHEN is parsed on your machine, and the raw string never reaches the
server — it only ever sees the resulting schedule and timezone. Parsing
happens after the timezone is settled, so unless you pass --tz the CLI
first looks up your account's timezone, one network call.
Any other value is refused client-side as a usage error before the schedule is created. A value containing the word "weekday", or with four or more spaces in it — the CLI's rough heuristic for "this looks like a cron expression" — gets a specific message saying weekday subsets and cron expressions aren't schedulable yet.
Anything else unparseable gets a generic "couldn't parse" error. Both list the three supported forms as the hint.
| Flag | Effect |
|---|---|
--run string |
required; the instruction that fires, up to 4,000 characters |
--tz string |
an IANA timezone name (America/Chicago, Europe/London); without it, your account's timezone, fetched live, falling back to this machine's local zone if that lookup fails; if neither can be named, a usage error asks for --tz |
--channels string |
where each run's report goes, comma-separated, from thread, inbox, email, push, and user_email (default thread,email); any other name is a usage error before anything is created |
--dry-run |
print what would be created instead of creating anything |
A create that works prints the new schedule's short id:
✓ schedule sc_1a2b created · daily, next fire 2026-09-04T07:00:00-04:00 · delivers to thread, email
Creating takes two steps: the task, then its delivery channels (and, for
hourly, its cadence). If camy.ai refuses the second step, the CLI
deletes the half-made task and shows the refusal, so you're never left
with a task that isn't the one you asked for. If that delete fails too,
the error names the task and the camy schedule delete command that
removes it.
A schedule made with schedule create before 1.0.4 never ran its
instruction. If camy schedule still lists one, delete it and create it
again.
--dry-run prints a one-line summary in human mode, the exact request
body under --json:
camy schedule create "hourly" --run "check inbox" --tz America/New_York --dry-run✓ dry run — would create: check inbox · hourly (0 * * * *, America/New_York), next fire 2026-09-03T15:00:00-04:00 · delivers to thread, email
It never creates anything, but unless you pass --tz it still reads your
account timezone over the network first. If that lookup fails, the dry run
silently resolves against this machine's local zone, so what it prints can
differ from what a real create would use.
camy schedule pause sc_9f8e
camy schedule resume sc_9f8e
camy schedule delete sc_9f8eID is the short id the list prints (sc_9f8e), a prefix of at least 4
characters, or a full id, resolved against every kind of schedule
together. pause works on everything except the reminders and timers an
agent set; those can only be deleted, and trying gives a usage error
pointing at delete instead.
resume undoes pause, and the schedule fires again:
✓ resumed sc_9f8e
resume refuses any reminder or timer an agent set, with a usage error.
That includes a timer the agent paused, which the list shows as paused; ask
the agent in a chat to resume it, or delete it. When most of a scheduled
task's recent runs failed, camy.ai
may decline to resume it: the command exits 1 with the reason, and
--force resumes it anyway.
delete works on every kind: it cancels an agent's reminder or timer, or
deletes anything else, whichever the id resolves to. It takes several ids
and asks for confirmation once, before acting.
camy schedule update sc_1a2b --cron "0 8 * * *" --tz America/Chicago --channels thread,email
camy schedule run-now sc_1a2bupdate and run-now act on scheduled tasks only, the kind
schedule create makes. They take the short id the list prints; a short
id that belongs to a reminder, a timer, or another kind of schedule is a
usage error.
update changes the task's cron (five fields), timezone, or delivery
channels in place, and needs at least one of --cron, --tz, or
--channels. It prints the next fire; when the task has already missed
one, it says it's overdue and fires on the scheduler's next pass instead,
and when there's no next fire to report, it prints none.
run-now fires it outside its schedule, on the next tick, about 30
seconds later.
See camy schedule,
camy schedule create,
camy schedule pause,
camy schedule resume,
camy schedule delete,
camy schedule update, and
camy schedule run-now for the full
flag list. You can also print the WHEN grammar from the binary itself with
camy docs:
camy docs timeA run is one firing of something that works on its own: a job, a
scheduled task, a schedule, a web monitor, or a standing goal. camy runs search looks through your runs, and through what your agents wrote while
they ran.
camy runs search "timeout"
camy runs search "invoice" --status failed
camy runs search "timeout" --offset 25Prints up to two lists. First the runs that matched: what ran, its state,
and how long ago. Then "What your agents said": each matching piece of an
agent's output, with its title, state, and age, and an excerpt with the
matching words in bold. A line under the runs says when more matched than
it shows, and names the flag for the next page, as in
--offset 25 for the next page. A line under "What your agents said"
appears whenever that list came back full, so more may have matched. Runs
are listed without ids, since no command takes one. Past the last run, a
page shows no runs and repeats "What your agents said" unchanged. The line
no more runs matched "timeout" past offset 25 appears only when nothing
your agents said matched either.
QUERY... is one or more words, joined with spaces, up to 200 characters.
| Flag | Effect |
|---|---|
--status string |
one of running, completed, dispatched, skipped_empty, needs_attention, failed; anything else is a usage error before any network call |
--source string |
one of scheduled_agent, kernel_schedule, web_monitor, standing_goal, checked the same way |
-L, --limit int |
how many runs, 1 to 100 (default 25), newest first |
--offset int |
skip that many runs (default 0); a negative value is a usage error before any network call |
--status and --source narrow the runs list only, and --offset pages
it. "What your agents said" matches on your words alone; it isn't filtered
by either flag or paged by --offset.
--source narrows to the last four kinds of run above only; it has no
value for jobs, so a job's runs show up only when --source is left off.
If search isn't on for your account yet, camy runs search and
camy jobs search both say so and exit 1. Past 30 searches a minute you
get the rate-limit exit (5).
See camy runs and camy runs search for the full flag list.
Quick to-dos, separate from jobs and schedules — nothing here fires on its own.
camy tasksLists tasks under a count of how many are open: a mark, a short id such
as tk_2b28, the title, and the due date when one is set. An open task
shows an open circle and a done task a check. An open task whose due date
has passed reads overdue and is marked !; a done task never does.
camy tasks add "renew passport" --due 2026-11-01 --priority high
camy tasks add "call the accountant about Q3"TITLE... is one or more words, joined with spaces. --due takes an ISO
8601 date, sent as-is with no local format checking. --priority must be
exactly low, medium, or high — anything else is a usage error before
any network call.
camy tasks done tk_2b28
camy tasks reopen tk_2b28
camy tasks rm tk_2b28done marks a task complete, with no confirmation needed, and prints the
camy tasks reopen command that undoes it. reopen puts a done task back
on the list. rm deletes it and asks for confirmation first. All three
take several ids, each a short id or a prefix; rm asks once for the
whole set.
See camy tasks, camy tasks add, camy tasks done, camy tasks reopen, and camy tasks rm for the full flag list.
camy capture [TEXT | -] [--title TITLE]Sends text into Camy's memory intake — a place to drop a note, a quote, or a stray thought without opening a chat.
camy capture "call the accountant about Q3"
camy capture "meeting notes" --title "Q3 sync"
pbpaste | camy capture -Text comes from three places, in this order: a literal - reads stdin; no
arguments at all, with something piped in (stdin isn't a terminal), also
reads stdin; anything else is the joined argument text.
A bare camy capture with nothing piped and nothing typed reads no stdin
and fails immediately with "nothing to capture" rather than hanging
waiting for input.
A capture holds up to 20,000 characters, and a --title up to 500.
Anything longer is a usage error before it's sent, never cut short, and so
is piped input over 1 MiB.
See camy capture for the full flag list.
camy integrationsLists connected accounts — calendar, mail, and similar providers — with a
rollup of what each one knows: an email address, or an event or message
count. When a sign-in has failed, the row reads reconnect and shows the
error; mail and calendar are checked separately, so a Google or Microsoft
account can show one of each. An account that stopped working altogether
reads reconnect, even with no error to show, rather than
not connected. A Google or Microsoft account whose mail or calendar
still works reads reconnect only when there's an error to show.
Accounts that still work are listed first, including one whose mail or
calendar half needs a reconnect. Then come accounts that stopped working
entirely, then anything never connected. When accounts need reconnecting,
the next step under the list names the first of them as
camy integrations connect takes it, such as
camy integrations connect github. For a Microsoft account that's
outlook or microsoft_calendar, whichever sign-in broke, since mail and
calendar are separate Microsoft sign-ins. For a Google account it's
google, which means gmail, even when it's Google Calendar that broke,
so it isn't sure to fix the calendar. If your organization has disabled a
provider, that's called out in a trailing line.
camy integrations health
camy integrations health gmailA shallow check across every provider, or just one. Each row shows a
status (healthy, unknown, not connected, or a warning), and whatever detail
is available: a last error, when a token expires, or when the last sync
happened. A provider you never connected reads not connected, not as a
warning. A tool server you added that is turned on is listed under its
own name, or app and a short id when it has none. A paused one isn't
listed.
google and microsoft, the names camy integrations lists those
accounts under, are read as gmail and outlook. Any other PROVIDER is
passed through as typed, so a typo surfaces as a not-found error rather
than a specific "unknown provider" message.
camy integrations connect google
camy integrations connect github --no-browserAsks camy.ai for a sign-in link, opens it in your browser, and waits while you sign in on the provider's own page. The link has to be opened within the time it prints; the sign-in itself can take as long as it takes. The wait ends when your sign-in lands: the account works, and it changed since before the link opened. Reconnecting an account whose old sign-in is still stored doesn't end the wait early. When your sign-in lands:
✓ gmail connected
If you sign in again to an account that was working but leave out some of
what Camy asks for, the wait stops with
gmail signed in, but Camy needs more permissions. Run
camy integrations connect gmail again for a fresh link, and allow
everything the sign-in asks for. On a first connect, a Google sign-in
missing permissions leaves the account not connected, so the wait ends as
it does when the link runs out.
PROVIDER is a provider's own name: gmail, google_calendar,
outlook, microsoft_calendar, github, slack, zoom, twitter,
facebook, instagram, oura, whoop, or tesla, which is also what
shell completion offers. google means gmail, and microsoft means
outlook, Outlook mail: each is the mail account's sign-in. Microsoft's
calendar is a separate sign-in. A provider that doesn't connect
from a terminal is a usage error pointing at camy.ai.
The wait lasts up to six minutes; Ctrl-C stops waiting, and nothing is
connected until you finish in the browser. If it runs out, the command says
the account isn't connected yet and suggests running it again for a fresh
link. If the account already worked and nothing about it changed, it says
gmail is connected instead, since it can't tell whether your sign-in went
through, and points at camy integrations health gmail. It says the same,
without waiting further, when Camy couldn't read the account before the
link opened and finds it working on its first look.
| Flag | Effect |
|---|---|
--no-browser |
print the link instead of opening it |
Under --no-input, or when stderr isn't a terminal, the command prints the
link and returns without waiting; --no-input also leaves the browser
closed. Run camy integrations afterward to see the account.
Disconnecting an account isn't a CLI operation; do that at camy.ai/p/settings/integrations, where you also connect the providers that don't connect from a terminal.
See camy integrations, camy integrations health, and camy integrations connect for the full flag list.
camy webhooksLists your webhook endpoints: ● when the endpoint is active and ○ when
it is not, then a short id such as wh_a1b2, the URL, and its state.
Creating or removing an endpoint isn't a CLI operation — the CLI only lists
endpoints and works with their deliveries.
camy webhooks deliveries wh_a1b2
camy webhooks deliveries wh_a1b2 --all --jsonLists delivery attempts for one endpoint, newest first, with a mark for
success or failure, the response status code (— when the endpoint never
answered), whether it was delivered or failed, the event type, and when it
happened.
--limit/-L (default 30 here, 100 for camy jobs) and --offset page
manually; --all auto-paginates, keeping whatever it already fetched if a
later page fails, the same partial-result contract as camy jobs --all.
--limit takes 1 to 200 and --offset can't be negative; anything else is
a usage error before any network call.
camy webhooks dead-letters wh_a1b2Lists the deliveries that ran out of retries, newest first: a short id
such as dl_90ff, the last response status code, dead or replayed,
the event type, why it gave up, and when. These dl_ ids are what
replay takes; a delivery attempt from deliveries is not one.
It shows the newest 200. When all 200 come back, a line under the list
says the newest 200 shown — there are more past these.
camy webhooks trigger wh_a1b2Sends a test delivery synchronously through the same delivery path a real event takes, so you see the endpoint's actual response rather than a queued attempt:
✓ test delivery sent — HTTP 200
If the endpoint didn't take the delivery, trigger fails (exit 1) and says
why: the endpoint's error, the HTTP status it answered with, or that it
never answered.
camy webhooks replay wh_a1b2 dl_90ffRe-enqueues one dead-lettered delivery under a fresh idempotency key, so it's retried as a new attempt rather than deduplicated against the failed one. A short dead-letter id is matched against that endpoint's newest 200 dead letters only, and one that matches none is a usage error. For an older dead letter, pass the full id (36 characters), which skips the lookup.
Both ids in this section take the short form their own list prints: the
endpoint id taken by deliveries, dead-letters, trigger, and replay
as camy webhooks prints it (wh_a1b2), and the dead-letter id in
replay as camy webhooks dead-letters prints it (dl_90ff). A prefix of
at least 4 characters, or the full id, works too.
See camy webhooks, camy webhooks deliveries, camy webhooks dead-letters, camy webhooks trigger, and camy webhooks replay for the full flag list.
camy jobs cancel, camy schedule delete, and camy tasks rm each ask
before acting:
cancel job jb_3f2a? [y/N]
Given several ids, they ask once for the whole set (cancel 3 jobs? [y/N]).
Anything other than y/yes cancels the operation. The prompt reads
/dev/tty directly, not stdin, so it never conflicts with a command that
also takes piped input elsewhere (camy capture -, for instance, stays
purely a stdin reader).
Running headless — --no-input, or no controlling terminal at all — skips
the prompt and fails closed with a usage error unless you pass --force:
camy jobs cancel jb_3f2a --force
camy schedule delete sc_9f8e --force
camy tasks rm tk_2b28 --forceWhen some of several ids fail, the rest still go through: camy lists the ones that didn't work and exits with the worst code among them.
This is camy's lighter confirmation tier. A few irreversible commands
(camy auth logout --revoke,
camy uninstall) use a stricter one where
--force is not enough and you type the word back or pass --confirm — see
Scripting with camy and Exit codes.
Every command in this document supports --json. Shapes vary by command:
-
camy jobs,camy tasks,camy webhooks,camy webhooks deliveries,camy webhooks dead-letters,camy integrations— a JSON array of rows: the CLI unwraps the server's list envelope, but each row is passed through field for field. An empty list is[]. Add--rawfor the server's own envelope instead (except on an--allsweep, which stays an array). -
camy jobs --all/camy webhooks deliveries --allon a mid-sweep failure —{"partial": true, "results": [...], "rows": N, "error": "..."}, still a non-zero exit. -
camy jobs search,camy runs search— the server's whole answer as one object, not an array, so it carries whether more matched:truncatedfor jobs;has_more, theoutput_matcheslist, andoutput_matches_truncatedfor runs.truncatedandoutput_matches_truncatedmean the page was full and there may be more;has_moreis exact. -
camy jobs show ID— the full job object as the server returns it. -
camy webhooks trigger ID— the test-delivery result the endpoint returned, not the endpoint row. It prints even when the event wasn't delivered, and the command then exits 1. -
camy schedule— one array of every kind of schedule, in the order they're read rather than by next fire: other schedules first, then an agent's reminders and timers, both as the server sends them, then scheduled tasks, each trimmed toid,type("scheduled_task"),name,label,status,recurrence_rule,next_fire_at(nullwhen it won't fire or can't be worked out),cron,timezone,channels, andcreated_at. The kinds have different shapes. -
camy schedule create --dry-run --json— the request body that would have been sent, never sent: the task's name, the prompt around your instruction, and its schedule. For example:camy schedule create "hourly" --run "check inbox" --tz America/New_York --dry-run --json --jq '.schedule_config'
{"cron":"0 * * * *","mode":"scheduled","timezone":"America/New_York"}The delivery channels are set in a second step after the task is created, so they aren't in this body.
-
camy capture,camy tasks add,camy schedule create(without--dry-run) — the created object as the server returned it; forschedule create, with the delivery channels added underdelivery_config. -
camy jobs cancel,camy schedule pause,camy schedule resume,camy schedule delete,camy tasks done,camy tasks reopen,camy tasks rm— a small confirmation object, for example:{"ok": true, "job_id": "a1b2c3d4...", "cancelled": true} -
camy jobs run-now,camy schedule run-now— a confirmation object with an extra field noting when it fires:{"ok": true, "job_id": "a1b2c3d4...", "fires": "next tick (~30s)"} -
camy jobs show,camy jobs cancel,camy schedule delete,camy tasks done,camy tasks reopen,camy tasks rmgiven several ids — an array with one object per id: what that id returned, plusref(what you typed),ok, the fullidonce it resolved, anderrorwhen that id failed. Given one id, they emit the single object shown above. -
camy schedule update— the updated schedule as the server returns it. -
camy webhooks replay—{"ok": true, "endpoint_id": "...", "replayed": "<dead letter id>"}. -
camy integrations health— the raw server response object. -
camy integrations connect— the sign-in link as camy.ai returned it, with the provider's name and how long the link can be opened; nothing opens and nothing waits.
Apart from the scheduled tasks camy schedule trims, none of these shapes
are scrubbed the way
camy approvals --json is (see
Approvals) — what the server sends is what you get, field
for field.
- Exit codes — auth (3), usage (2) from a bad
WHENor a refused confirmation, and the rest of the frozen table - Scripting with camy —
--json,--jq,--template,--no-input, and using camy from cron - Approvals — how a pause for a human works, for anything an agent stops on rather than a scheduled fire
- Inbox, sweep, and feed — the other place things arrive without a chat turn