A scheduled automation is a background sidecar ("builtin": "schedule")
that runs on a cron schedule and starts a fresh agent conversation (agentapi new-conversation) on each run.
This skill is strictly for scheduled (cron) automations. Do not use it to
create UI sidecars, continuous generic command/daemon sidecars, or in-turn
timers (use the schedule tool instead).
Quick Start (5-Turn Creation Flow)
- Turn 1 — Cadence: Ask via
ask_question(Hourly,Daily,Weekly, orCustom cron schedule). - Turn 2 — Time / Day: Ask for the specific time or day of week
(
ask_question). - Turn 3 — Task Prompt: Ask what the agent should do on each run and refine into a self-contained prompt.
- Turn 4 — Write
sidecar.json: Create
~/.gemini/jetski/sidecars/<slug>/sidecar.jsonwith"builtin": "schedule","args": {"schedule": "<cron>", "prompt": "<prompt>"}. - Turn 5 — Optional Test Run: Offer to test the prompt immediately via
agentapi new-conversation.
Interactive Creation Workflow
Guide the user through creating the automation one step at a time across turns. If the user already provided some details in their initial prompt (such as the schedule or the task), skip the questions already answered and proceed to the next missing step.
Turn 1: Ask for the Cadence
If the schedule cadence is not yet specified, use the ask_question tool to
ask:
- Question:
"What should be the cadence of the automation?" - Options:
HourlyDailyWeeklyCustom cron schedule
Wait for the user's response before moving to the next question.
Turn 2: Confirm the Specific Time / Day
Based on the chosen cadence, confirm the exact schedule in a follow-up turn
using ask_question:
- If Daily: Use
ask_questionto confirm the hour of the day (e.g.,9:00 AM,12:00 PM,5:00 PM; the user can also enter a custom time via the built-in write-in option). - If Weekly: Use
ask_questionto confirm both the day(s) of the week (e.g.,Monday,Friday,Weekdays (Mon–Fri)) and the hour of the day (e.g.,9:00 AM,5:00 PM). - If Hourly: Default to the top of every hour (
0 * * * *), or confirm if they want a specific minute offset. - If Custom cron schedule: Ask the user to specify their desired cron
expression or interval (e.g.,
*/30 * * * *for every 30 minutes).
Wait for the user's response before asking what the task should do.
Turn 3: Ask What the Task Should Do
Once the schedule is set (and if the task itself has not been described yet),
ask the user in plain text (do not use ask_question for this open-ended
step):
"What would you like the task to do? (For example: 'Summarize my unread
emails from the last 24 hours and highlight any that need a reply' or 'Check
my open pull requests and list any with failing checks.')"
Wait for the user's response.
Step 4: Create sidecar.json & Offer a Test Run to Configure Permissions
1. Translate Schedule & Author Self-Contained Run Prompt
- Cron schedule: Standard 5-field cron expression (
minute hour day-of-month month day-of-week) written in the user's local time, always prefixed withCRON_TZ=<IANA zone>so it runs in the user's timezone:- Hourly:
CRON_TZ=America/New_York 0 * * * * - Daily at 9:00 AM:
CRON_TZ=America/New_York 0 9 * * * - Daily at 5:00 PM:
CRON_TZ=America/New_York 0 17 * * * - Weekly on Monday at 9:00 AM:
CRON_TZ=America/New_York 0 9 * * 1 - Weekdays at 9:00 AM:
CRON_TZ=America/New_York 0 9 * * 1-5
- Hourly:
- Determine the user's timezone (an IANA name such as
Europe/Zurich;
never an abbreviation likePSTor a raw offset like+02:00):- If the user already stated a timezone or city, use the matching IANA
zone. - Otherwise detect the host's timezone (map any OS-specific zone name to
its IANA equivalent). - If detection fails, use
ask_questionto confirm the user's timezone
(offer the detected zone plus a few common zones; the user can write in
their own). - If the user supplies a custom cron that already starts with
CRON_TZ=
orTZ=, keep it as-is and do not add a second prefix. - When confirming the schedule to the user, state it with the zone (e.g.,
"every day at 9:00 AM Europe/Zurich time").
- If the user already stated a timezone or city, use the matching IANA
- Self-contained prompt: Each scheduled run starts a brand-new conversation with no memory of prior runs. Write a clear, self-contained prompt stating the data sources, actions, and desired output format.
2. Announce Automation Creation & Write <configDir>/sidecars/<sidecar-id>/sidecar.json
Before calling write_to_file, always output a short message to the user
stating that you are now creating the <display_name> automation (do not
mention sidecar.json or internal file details to the user). Also set
toolAction / toolSummary on write_to_file to "Creating <display_name> automation".
Create the configuration file at:
<configDir>/sidecars/<sidecar-id>/sidecar.json
<configDir>is the user's.gemini/configdirectory (typically
~/.gemini/config).<sidecar-id>is a short, uniquekebab-caseidentifier derived from the task (e.g.,daily-pr-check).- Choose a clear, human-readable
display_name(e.g.,"Daily PR Status Check"). You MUST tell the user this exactdisplay_namewhen pointing them to the Automations dashboard so they know which automation to enable. - Use snake_case field names only (
restart_policy,display_name,agent_permissions,access_grants,workspace_uris). - Use lowercase string literals for
restart_policy("always"is required for"builtin": "schedule"and continuous daemons;"on-failure"or"never"apply only to one-shot"command"sidecars) — never proto enum names like"SIDECAR_RESTART_POLICY_ALWAYS"or"unless-stopped". - Never place
sidecar.jsonor scripts inside an ephemeral CitC workspace (/google/src/cloud/<user>/<workspace>/...) or point symlinks in~/.gemini/config/to an ephemeral CitC workspace that may later be deleted.
[!CAUTION] Never Hallucinate Tools or Permissions: - Do NOT guess or
invent MCP servers (mcp(...)) or CLI commands (command(...)) that you have
not verified exist in the current environment. - Only include an
mcp(<server>/<tool>)grant if<server>is actually present in your
<mcp_servers>system prompt block. - Only include acommand(<prefix>)
grant if you have verified the binary/subcommand exists (e.g., via an
available skill or a live test run). - Never use overly generic wildcards
(command(*),read_file(*),read_file(/),write_file(*),mcp(*),
read_url(*)) or invalid wrapper syntax likeallow(*).
Example sidecar.json
{
"builtin": "schedule",
"args": [
"CRON_TZ=America/New_York 0 9 * * *",
"agentapi",
"new-conversation",
"--",
"Check open pull requests in the repository and summarize any with failing CI checks or pending review comments."
],
"restart_policy": "always",
"display_name": "Daily PR Status Check",
"description": "Every day at 9:00 AM (America/New_York), checks open pull requests and summarizes failing checks or review comments.",
"agent_permissions": {
"access_grants": [
"command(gh pr list)",
"command(gh pr view)"
]
}
}
args[0]must be the full cron schedule as a single string, including theCRON_TZ=<zone>prefix (never omitargs[0]or place the executable atargs[0]when"builtin": "schedule"is set).- Always use absolute paths for any local script arguments in
args(never bare relative filenames like"watcher.py"or paths inside ephemeral workspaces that may later be deleted). - Always include
"--"immediately before the prompt string inargsso the prompt is cleanly separated fromagentapi new-conversationflags.
3. Point to the Dashboard (with Automation Name) & Ask to Test-Run for Reliable Permissions
[!CAUTION] DO NOT enable the automation yourself. Never modify
user_config.jsonto set"enabled": true, and never invoke any command or
RPC to start or enable the sidecar.
After writing sidecar.json:
- Tell the user that the automation
<display_name>(<sidecar-id>) has been created, and explicitly instruct them to enable it in the Automations dashboard using the action button:[Open Automations Dashboard](sidecar://dashboard) - Explain to the user that once enabled, the automation will run in a project that inherits global permissions and presets, and all other non-approved commands will be auto-denied. To ensure that the automation can proceed successfully and unattended, you can execute a test run right now to configure the permissions properly.
- Use
ask_questionto ask the user if they want you to execute a test run
now:- Question:
"Once enabled, '<display_name>' will run in a project that inherits global permissions and presets, and all other non-approved commands will be auto-denied. Would you like me to execute a test run now to configure its permissions properly so it can proceed successfully?" - Options:
(Recommended) Yes, execute a test run now to configure permissionsNo, I'll review permissions and enable '<display_name>' in the Automations dashboard
- Question:
Step 5: If the User Chooses to Test-Run the Task Now
When the user agrees to a test run:
- Execute the task once in the current conversation:
- Search for and read any relevant skills (
skill_search/view_fileon
SKILL.md) or check available<mcp_servers>needed to fulfill the
task. - Run the actual commands, file reads/writes, URL fetches, or MCP tools to
perform the task once. - If the required tool/integration does not exist or needs
authentication/setup, inform the user clearly so they know what is
missing before enabling the automation.
- Search for and read any relevant skills (
- Update
sidecar.jsonwith the exact verified permissions:- Record every permission grant actually required during the test run,
scoped as succinctly as possible inagent_permissions:workspace_uris:["file:///absolute/path/to/dir"]if the task
needed read+write access to a workspace folder.access_grants:command(<binary_and_subcommand>)— e.g.,command(gh pr list)
(nevercommand(*)).read_file(<absolute_path>)— e.g.,read_file(/Users/alice/notes)
(neverread_file(*)orread_file(/)).write_file(<absolute_path>)— e.g.,
write_file(/Users/alice/digests)(neverwrite_file(*)or
write_file(/)).mcp(<server_name>/<tool_name>)— e.g.,mcp(buganizer/get_bugs)
(only for real MCP tools actually called; nevermcp(*)).read_url(<domain>)/execute_url(<domain>)— e.g.,
read_url(github.com)(neverread_url(*)).
- Also update the prompt in
argsif the test run revealed specific skill
paths or CLI flags that will help future scheduled runs succeed reliably
using those exact granted commands.
- Record every permission grant actually required during the test run,
- Final confirmation with the Automation Name:
- Summarize the verified permissions added to
<display_name>
(<sidecar-id>) and remind the user to enable<display_name>in
the Automations dashboard:[Open Automations Dashboard](sidecar://dashboard)
- Summarize the verified permissions added to