Routines & Runs
A Routine is a scheduled, recurring piece of AI work. A schedule, a markdown brief, an on/off switch. Every execution becomes a Run with a captured log — and, when it uses a browser, a visual recording you can review beside that log.
Where they live
Routines have their own section in the nav, under AI → Routines. That list is company-wide: every routine, every employee, one page. Narrow it with the search box at the top, or filter by the AI Employee a routine is assigned to, or by health — Active, Paused, Needs attention. Two more axes group routines across employees: folders in the sidebar, and company Tags as chips above the list.
Clicking a routine opens its detail page: Overview, Brief, Runs, and Settings, with Ask AI in the header. Each AI Employee links to their own slice of that list from Settings → Routines — same page, filtered to them.
Searching the list
Folders ask where does this live and tags ask what is this about — both want you to know the answer before you can narrow. The search box above the list is the third question: what was that thing called? Type into it and the list narrows as you go, matching everything the row already shows.
- The routine's name, and its slug — so a link somebody pasted still finds the routine after it was renamed.
- The AI Employee it is assigned to.
- The folder it is filed in, by full path — searching
Financefinds everything underFinance/Month-endtoo. - Its tags.
- Its schedule, in any dialect:
0 9 * * 1-5,weekday— the words the row itself shows, “Every weekday at 9:00 AM” — andMondayall find the routine that runs on weekday mornings. The cron expression and both plain-English renderings are searched together, so it does not matter whether you remember a schedule by its cadence or by the days it names.
Several words are all required, and they may land in different fields — finance digest finds the digest filed under Finance. Case and accents are ignored. Press / anywhere on the page to jump into the box and Esc to empty it.
Folders
Once a company runs dozens of routines, neither "all of them" nor "one employee's" is a useful view. Folders are the filing tree in the Routines sidebar: company-wide, nestable up to five levels, and exclusive — a routine is filed in at most one folder, or in none at all.
Create one with the folder button at the top of the sidebar, or from New folder… in any move menu. Selecting a folder narrows the list to that folder and everything nested inside it, so a parent never reads as empty just because its routines live one level down. The tag chips narrow with that same folder scope, so every tag shown can match a routine currently in the list. Unfiled at the bottom of the tree collects everything you haven't filed yet. Each folder's ⋯ menu holds New subfolder, Rename, Move to top level, and Delete folder.
Filing routines
To file an existing library, press Organize above the list. Checkboxes appear on every row: tick the ones you want (or Select all), then pick a destination from Move to folder. It is one request for the whole batch, so a failure never leaves half the selection moved. A single routine can also be re-filed from the Folder field on its Settings tab, and a new routine created while you are inside a folder lands there by default.
AI Employees can file their own work too: create_routine and update_routine both take a folder — a name like Finance or a path like Finance/Month-end. Any segment that doesn't exist yet is created, the same way tag names are. Passing an empty string to update_routine unfiles the routine.
Anatomy
- name
- What humans call this routine.
- folder
- Which folder the routine is filed under. Optional — a routine with no folder shows up under Unfiled.
- cron
- When it runs. You build this from the Schedule control — a cadence, the days, a time — and Genosyn compiles it to a standard 5-field cron expression. See Scheduling.
- body
- Markdown brief — what the employee should do when this fires. Stored on
Routine.body. - enabled
- Boolean. Disabling stops the schedule without losing the row — the ordinary housekeeping switch. To stop work during an incident, place a Standdown instead; it records who and why, and reaches surfaces this switch does not.
- approvalRequired
- Optional. If true, the runner records the intended action and blocks it on a human ✓ via the
Approvalentity. - model
- Optional. Which of the employee's AI Models this routine runs on. Defaults to Inherit — whichever model is active for the employee. See Picking a model.
- timeoutSec
- Hard timeout in seconds. The runner aborts the in-process agent after this long and marks the Run
timeout. Defaults to 60 minutes and is editable per routine (10s – 6h) from the routine editor — raise it for long jobs, lower it to fail fast. - catchUpPolicy
- What to do about slots missed while the server was down. Run once (the default) fires a single catch-up run; Skip declines it when the slot is already more than a minute late. See Downtime and recovery.
- maxAttempts
- Total attempts per scheduled occurrence, counting the first. 1 by default — failed and timed-out Runs do not retry, while a newly interrupted initial scheduled Run on an enabled routine without an approval gate still receives one recovery attempt an hour after Genosyn marks it. Higher limits also bound interrupted retries later in the same chain. Paired with
retryBackoffSecandretryOnTimeout. - browserEnabledOverride
- Optional per-routine override of the employee's browser toggle — force it on for a research routine, or off for one that must never touch the web. Unset means "inherit from the employee".
- acceptanceCriteria
- Optional plain-language definition of done, edited at Settings → Outcome check. When set, the criteria ride along in every Run's brief and each completed Run is graded against them. See The outcome check.
Scheduling
The Schedule control asks when the work should happen, not how to spell it. Pick a cadence and the control offers only what that cadence needs:
- Every few minutes — 1, 2, 5, 10, 15, 20 or 30.
- Hourly — every 1 to 12 hours, at a chosen number of minutes past.
- Daily — a time of day.
- Weekly — any set of weekdays, plus a time. Mon–Fri reads back as “Every weekday”.
- Monthly — a day of the month and a time.
- Yearly — a month, a day, and a time.
Underneath, the control writes a plain English sentence, the cron expression it compiled, and the next few times the routine will actually fire — so you can check the schedule before you save rather than after the first Run lands. Times are server-local. The same control appears on Revenue Signals and on a Pipeline schedule trigger.
Writing cron by hand
Genosyn stores the schedule as a standard 5-field node-cron expression, and the control's Custom (cron) option lets you write one directly. Cron can say things the cadences above cannot — two fixed times a day, second-level granularity, the 13th and every Friday — and a routine already on such an expression opens in the custom field with it intact rather than being rounded to the nearest cadence.
┌───── minute (0 - 59)
│ ┌─── hour (0 - 23)
│ │ ┌─ day of month (1 - 31)
│ │ │ ┌─ month (1 - 12)
│ │ │ │ ┌─ day of week (0 - 6, Sunday = 0)
│ │ │ │ │
0 9 * * 1-5 → weekdays at 09:00
*/15 * * * * → every 15 minutes
0 9,17 * * * → 09:00 and 17:00, every dayAI Employees writing a routine through create_routine or update_routine pass the cron expression the same way they always did — the control is how humans are asked, not a change to what is stored.
Cron is not the only way a routine fires. A Trigger subscribes a routine to a resource family — deals, mail, Runs, Goals — and fires it whenever that family changes anywhere in the company, with a per-trigger minimum interval so a busy family can't hot-loop it. Gated routines still meet their Approval. See Reactivity.
The brief
The body is markdown the model reads at run time. Keep it short and verb-first. Reference a Skill by name if the playbook already exists; otherwise describe the desired outcome.
# Morning brief
Every weekday at 09:00, post a 5-bullet summary of:
1. Stripe revenue for the last 24h (call `reconcile-stripe-payouts`)
2. New customer signups (Postgres connection "prod-read")
3. Open PRs assigned to humans (GitHub connection "main")
4. Anything new in #alerts since yesterday
5. One sentence of your own opinion about the day
Post it to the #morning channel.Ask AI about a routine
You can paste screenshots into the AI message box, drag files onto it, or use the paperclip. Review and remove attachments before sending. See image formats and limits.
Every routine has its own AI chat. Press Ask AI in the routine header and a panel docks beside the page — the same idea as the chat beside an email, pointed at scheduled work instead. Drag its left edge to resize it, or wind it down to a spine with the chevron; it stays how you left it next time.
The employee that owns the routine answers by default, because the question is usually about their work. They are handed the routine itself before they read your message: the schedule and every setting, the brief, how the last ten Runs went, and the tail of the newest Run's log. So “why did last night's run fail?” is answered from the transcript rather than guessed at — and you never have to paste a log in. Type @ to hand the question to somebody else, # to reference another company resource, or /new on its own to clear this routine's context.
Asking is not editing. Any Member who can open a routine can ask about it, while changing one still needs an admin — and the employee is told to describe a change rather than make it. If you do ask for the change and you have the rights to make it, it runs with your authority, and whatever it did shows up as a small action pill under the reply. You can attach a file to the question too — a spec to check the brief against, a log from somewhere else.
The working status remains visible beside the composer throughout the reply. Keep typing or attaching files and press Queue message to add a follow-up. Pending messages appear above the composer and send one at a time after the preceding reply finishes; remove a message before it starts if it is no longer needed. The queue stays with this routine's conversation as you navigate around the app. If a reply fails, pending messages remain available for you to resume.
Each routine's chat is independent, and a reply in progress belongs to the server rather than to your browser tab. A long answer shows as working; if the connection drops the panel says reconnecting and picks the same reply back up when it lands, so closing the panel, changing tabs, or reloading is safe. A reply that genuinely could not run — the server restarted mid-answer, or the employee stayed busy for several minutes — says so and offers Try again. When the answering employee has more than one connected AI Model a selector appears under the composer, and the conversation stays on whichever model answered last.
Chat and Runs continue in parallel
Starting a Routine does not make its AI Employee unavailable. You can keep chatting with that employee and start other independent Routines while the first Run continues. Genosyn places no per-company ceiling on overlapping top-level AI work. Chat threads are independent too: one AI Employee answers several conversations at once, and only a second message in the same thread waits for the reply ahead of it. Your deployment operator and AI Model provider still determine real capacity, cost, and rate limits.
Parallel delegation
API-key and custom-endpoint Chat turns and Routine runs include delegate_parallel_work. An AI Employee can split an objective into independent briefs, run up to four temporary copies of itself at once, and receive their ordered results before it writes the final answer or takes follow-up action. Each worker uses the same Soul, Skills, AI Model, Grants, secrets, and timeout as its parent.
Research our weekly launch brief in parallel:
1. Summarize customer feedback from the support mailbox.
2. Compare this week's Stripe metrics with last week.
3. Review merged GitHub pull requests for customer-visible changes.
Verify the three results, resolve any disagreement, then post one concise brief to #launch.Copy/paste: one worker per GitHub issue
Before using this example, connect GitHub, allowlist the repository, and give the AI employee a Grant to that Connection. See GitHub & engineering grants.
Triage up to 12 open GitHub issues in acme/widgets.
Please use subagents for this task. Use one subagent for each GitHub issue.
First list the open issues and ignore pull requests. Give each temporary worker one issue number,
its title and body, and ask it to identify the likely cause, affected area, severity, missing
information, and a recommended next step. Verify the returned findings, then produce one table
ordered by severity with links to the issues.
This is read-only triage. Do not edit files, create branches, commit, push, or comment on issues.Replace acme/widgets with the allowlisted repository. The sentence about subagents is ordinary Routine instructions, not special syntax: the AI Model plans the work and calls delegate_parallel_work when that tool is available and the issue briefs are independent. Confirm the call in the Run log. If delegation is unavailable or unsafe, the employee should explain the constraint and continue serially.
- A delegation call accepts up to eight briefs, runs at most four at a time, and a top-level turn can delegate twelve briefs in total. Temporary workers cannot delegate again. For more than twelve issues, narrow the filter or split the review across separate Runs.
- Workers receive only their self-contained brief, not the parent chat history. Include the relevant dates, data sources, constraints, and expected output in each brief.
- Workers share the employee's working directory. Parallel reads are safe; for writes, assign distinct files and avoid concurrent git operations or overlapping edits.
- Delegation multiplies AI Model usage. The parent Run timeout still applies to every worker and aborts the whole group when it expires.
Employees manage their own routines
You don't have to click through the editor yourself — every AI Employee holds built-in tools for the full routine lifecycle: list_routines, create_routine, update_routine, and delete_routine. Ask an employee in chat to set up a weekly report, move it to Fridays, rewrite its brief, or pause it, and they edit the existing routine in place —update_routine covers rename, re-schedule, brief rewrites, and the enable/disable switch, so nothing forces a duplicate.
Every change made this way is written to the audit log, and creating or deleting a routine also lands in the owning employee's journal, so the humans can always see who rescheduled what.
Picking a model
An employee can hold several AI Models and keeps one active. By default a routine runs on that active model — the Model field in the routine editor reads Inherit, and the routine follows the employee whenever you switch their brain.
Pick a specific model instead to pin it. The routine then always runs on that model regardless of which one is active. This is how you put a noisy hourly digest on a cheap local endpoint while choosing a frontier model in employee Chat — or the reverse, pinning the weekly board report to your strongest model.
- You can only pin a model that belongs to that employee. Register it at the employee's Settings → Model first.
- A pin only affects this routine's Runs. Dedicated employee Chat has its own per-message picker when multiple models are connected; it defaults to whatever model that conversation last answered on, and to the active model for a new thread.
- Remove a pinned model and its routines quietly revert to Inherit rather than breaking. The run log names the model it used and whether it was pinned or inherited.
Runs
Every cron tick — and every manual trigger — creates a Run row. The runner runs the in-process agent in the employee's directory and stores the agent transcript — the model's messages and tool trace, not captured CLI stdout — on Run.logContent. It records what each tool returned, not only what was called, and an oversized transcript is elided in the middle rather than cut off at the cap: the ending is where a Run says what it did, and it is the last thing worth losing. While the Run is active, Genosyn checkpoints that transcript to the database about once a second, so it survives a server or container crash.
The transcript is still the model's account of its own work. What the server recorded the Run actually changing is the separate Effects list beside it — see what proves a Run worked. Home's AI Employee bubbles open each employee's day, where Runs show a concise outcome summary with their status and verification badges. Choose Open the run log there to read the full report and inspect its evidence.
A routine's full run history lives on its Runs tab — every Run, scheduled or manual, with the log viewer. If a Run actually opens a browser, Genosyn also captures a silent visual recording automatically, from that browser session's first activity until it finishes. Enabling Browser access alone creates no video, and browser recordings contain no audio.
The recording player sits beside the Run log, with a download for each finished MP4. A Run may have more than one when it delegates independent browser work; use the numbered Browser buttons above the player to switch between them. While a Run is active, the player says that capture is in progress, then updates when the file is ready.
- Status starts at
runningand ends at one ofcompleted,reviewed(proactive evidence review only),failed,skipped(no model was connected),timeout, orinterrupted(the server stopped mid-run). A Run stopped by the step-limit backstop — the model kept calling tools without ever finishing — is markedfailed, with the reason in the transcript. Completed only ever means the loop returned cleanly; whether the work met its bar is answered by the other two axes — this routine's Checks and its outcome check — never by the status. - Each Run also records the tokens it consumed — the provider's own per-turn counts, summed. They show on the Run log modal and roll up per employee and per routine at Settings → Usage.
- The Run detail view tails the transcript while it's running, then renders the full transcript when it's done.
- Manual Runs from the "Run now" button live in the same table as scheduled Runs.
- Retry a Run that
failed,timed out, or wasinterruptedstraight from its run history. It re-triggers the routine immediately, outside the schedule, and opens the live log for the new Run.
Recordings stay with the Run history. Deleting the Routine deletes its Run logs and browser recordings; deleting the company removes them too. They live in the App-private data directory and are included in whole-instance backups.
Failures are loud: a Run that ends failed, timeout, or interrupted with no retry still scheduled sends a bell (and web push) notification to the company's owners and admins and to the Member the employee reports to, deep-linked to the Run log. The Home page additionally shows a Failed routines panel for anything that broke in the last 24 hours — clicking a row there opens that Run's log over Home rather than sending you to the routine — and every Journal entry for a Run links straight to that routine's run history, where the Retry button is one click away. Once you've looked at a failure, hit the ✕ on its row to dismiss it — the run stays in the routine's history, but it drops off the panel (and out of the System Health failed-runs count) so it stops nagging the whole team. A dismissed failure still appears in the employee's work timeline, opened from their bubble on Home, alongside every Run that went fine. Acknowledging a failure keeps it in the account of what happened that day.
Every row on that panel carries a Retry button too, so the commonest answer to a broken Run doesn't cost a trip into the routine. It runs the routine again immediately, outside the schedule, and dismisses the Run it came from — which keeps the panel from inviting a second, duplicate Run. It confirms first, because a Run that stopped part-way through may already have sent the email or moved the money; read the log if you're not sure repeating the work is safe.
A failure the routine has already recovered from clears itself. If the routine has completed a Run since — the next scheduled tick, an automatic retry, or a Retry you clicked — the older failure drops off the panel and out of the System Health failed-runs count without anyone dismissing it. It stays in the routine's run history, where the Run log and the Journal still have it. The point is that a red panel on Home always means something is broken now: a panel that is usually stale is a panel people learn to scroll past.
The outcome check
A green completed proves the loop returned — it says nothing about whether the work was any good. A convincingly wrong Run used to look byte-identical to a great one. The outcome check is the second axis: give a routine acceptance criteria (Settings → Outcome check) — a plain-language definition of done, like "the digest was posted to #general and covers every failed run since the last digest" — and two things happen.
- The criteria ride along in every Run's brief, so the employee aims at the same bar it will be graded against.
- After a completed Run, a restricted checker — a zero-tool model turn on the same brain, reading the transcript as untrusted evidence beside the server-written Effects list — grades the work and stamps a verdict on the Run:
achieved,unclear(it looked and could not tell),off goal, orunverified(no judgement was ever produced — the checker errored or never submitted). The verdict shows as a chip beside the status everywhere Runs render, with the checker's one-line reason on hover and in the log view.
An off goal verdict notifies admins and the employee's manager the same way a failure does — convincing-but-wrong is exactly the failure mode a green checkmark hides. The verdict also lands in the employee's Journal entry for the Run, so the employee itself learns from past outcomes instead of only seeing that runs "finished". The check never changes the Run's status, and a routine with no criteria behaves exactly as before — no verdict, no extra model turn, no extra cost.
A routine can also declare which company Goal its work serves — the Goal picker on the Settings tab. The linked goal rides into every Run's brief beside the criteria, and the checker receives it as judging context: work that met the letter of the criteria while working against the objective is off goal.
Verdicts also feed forward: a Run that fails, times out, or grades off goal writes a Lesson into the routine's future briefs — see the improvement loop.
Checks
The outcome check is still a model reading a transcript another model wrote. A Check is the third axis and the only one with no model in it: a machine-verifiable assertion the Run must pass before it finalizes green, written by an operator on the routine's Settings → Checks panel.
A proactive Run with status Reviewed has examined evidence; delivery remains unverified and its delivery Checks have not run. Approving its proposal in the Decision stack starts a separate Run with the original Checks and outcome grading. A Check cannot authorize work beyond the approved plan.
- An effect Check counts what the server recorded this Run changing — at least one
mail.send, at most three. No shell, no model, no extra cost. - A command Check runs a shell command in the sandbox and passes on exit
0— a test suite, agit diff --exit-code, a script that checks the thing was deployed.
Every Check's result lands on the Run with its detail and how long it took, and the Run carries a checks verdict chip beside its status. A failing required Check earns the employee up to two more briefed attempts inside the routine's existing timeout — never more time, never a third round — and then finalizes as a failure that revokes waivers and writes a Lesson like any other. Checks ride into the Run brief, so the employee aims at the bar; no MCP tool can create, edit, or delete one. See what proves a Run worked.
Downtime and recovery
Servers restart, containers get rescheduled, laptops go to sleep. Two things can go wrong, and Genosyn handles them differently.
The server stopped mid-run
A Run that was executing when the process died can't report its own outcome — nobody was left to write the row. The scheduler notices on its next heartbeat and marks it interrupted, appending a line after the last durable checkpoint. The Run log still shows the model text and tool activity captured before the stop, so the final line identifies where the visible work ended. Nothing is known about work the employee did after that line, which is exactly why the status is its own word and not failed.
When Genosyn marks an initial scheduled Run on an enabled routine interrupted, it also records a durable recovery retry. At the default 1 attempt, exactly one recovery attempt becomes due an hour later. Raising Attempts lets later interruptions in that retry chain continue with the routine's configured jittered backoff, up to the five-attempt cap. Manual "Run now," webhook, and approval Runs are excluded. Pausing the routine or adding an approval gate before dispatch cancels the automatic attempt.
The server was off across scheduled slots
A routine fires once when the server comes back, never once per missed slot. An hourly digest that was down overnight produces one run, not twelve. The catch-up run records how many occurrences it stands in for — you'll see +11 missed on the run row — and its brief tells the employee to cover the whole period rather than just the last interval.
Set After downtime to Skip in the routine's Settings when a late run is worse than no run — a 09:00 standup digest arriving at 16:00 is noise. The skipped occurrences are recorded in the employee's Journal so the gap is still visible.
Retries
Retries after failed Runs are off by default. Raise Attempts above 1 in the routine's Settings to retry them automatically, up to 5 attempts, waiting a randomized, doubling interval between each (from Retry backoff, capped at six hours). Timeouts are opted in separately, because retrying one re-burns the routine's whole time budget. An interrupted initial scheduled Run on an enabled routine without an approval gate is the safety exception: even at 1 attempt, it receives one recovery attempt after an hour. Above 1, interrupted retries use the configured bounded backoff until the chain reaches its cap.
The retry itself is no longer blind about it. Attempt 2 opens with the Effects the server recorded during every earlier attempt in the chain — the emails that went out, the rows that moved — and is told to verify each one before doing it again. Deliberately "verify before redoing" rather than "skip": the ledger proves an action was recorded, not that whatever it touched downstream actually landed.
- Only scheduled Runs and Runs created by an automatic retry are eligible. A manual "Run now," a webhook, or an approved Run had someone present who saw the outcome, so nothing respawns behind their back.
- A run with a retry pending stays out of the Home Failed routines panel until its last attempt is spent — it isn't something to act on yet. It shows under Runs waiting to retry in System Health instead.
- Cancel retry from the run's log view stops the chain without pausing the whole routine — the escape hatch when you've decided to fix the failure by hand.
- These are operator settings. AI Employees managing their own routines through
update_routinecannot change them.
System Health
Settings → System Health (also a card on the Home page) rolls up everything that might be quietly broken for the company, over a 24-hour window:
- Failed runs — failures, timeouts, and restarts that interrupted a run, excluding anything already scheduled for a retry.
- Runs waiting to retry — an in-progress retry chain, so it's visible rather than silent. Nothing to do.
- Stuck runs — still
runningafter 8 hours. Crash recovery clears orphans within a heartbeat now, so anything here means the scheduler itself isn't running. - Skipped runs and employees missing an AI model — routines that never actually ran because no model was connected.
- Approvals waiting too long, email delivery failures, and integration connections in an error/expired state.
Every row deep-links to where you fix it — the routine's run history, the employee's model settings, the approvals inbox, or the relevant settings page. It is read-only and computed live from existing data, so there is nothing to configure.
Approvals
Some routines should not auto-fire. Flip approvalRequired on and the runner stops the moment the routine would take a sensitive action — raising an ad budget, sending an email, hitting a third-party API. The action is recorded as an Approval row. A company owner or admin must approve or reject it from a logged-in browser session; API keys and ordinary Members cannot open the inbox or decide approvals. Approval claims are one-shot, so double-clicks and concurrent reviewers cannot replay the action. If the approved action fails, the row moves to execution_failed for investigation instead of becoming eligible to run again. Replay payloads, provider results, and raw provider failures are never returned by the inbox API.
A pending Approval never expires, so a gated tick nobody answers is lost, not queued. Genosyn no longer lets that happen in silence: an Approval still pending after 24 hours re-pages the owners and admins with a stall reminder — once per row, so the bell nags exactly one extra time. Pending Decisions and overdue Handoffs get the same treatment; see the Decision Stack and AI Employees.
Built-in approval kinds
routine— the whole Run is gated.browser_action— a form submit from an employee whose Browser requires approval for submits.mcp_tool— a guarded tool on a company-configured MCP server. The call is snapshotted and replayed on approve.ad_spend— a spend-increasing ad-platform change above the Connection's threshold. See Paid Marketing.lightning_payment— a retired kind. Nothing issues one any more; it stays readable so Approvals decided before the Lightning connector was removed keep their meaning.