Documentation
What runs when nobody is looking
Three things Kicklace can do on its own overnight: read and tag the email that arrives, write one short brief in the morning, and watch for four named situations you would have spotted yourself if you had had the time. All three are off until you switch them on, and none of them can send anything.
Kicklace does three things on its own overnight, and it never sends anything.
- Triage — every email that arrives is read once and tagged by intent, and the matching reply is drafted on the person's record for somebody to send.
- The brief — one notice a morning saying what changed: who joined, who went quiet, what is waiting for approval, which drafts are ready, and which of your charts moved.
- Noticing — four named rules looking for the thing you would have spotted if you had time, each arriving with the work already written down.
All three are off until you switch them on, all three run inside the same worker that already refreshes the paragraphs at the top of your records, and all three obey the one rule everything here obeys: what it wants to send is a draft, and a person decides that it goes.
The direction behind it is docs/ai-centric-direction.md §4 and §10.
1. Triage is a starter, not a new engine
There is no separate triage system. Reply triage is one of the starters in
docs/blueprints.md, written in the ordinary automation language, and you read it, edit it and
switch it on like any other automation.
Settings → Setup → Starters → Reply triage installs, paused:
- an Intent field on a person — A question · A complaint · A cancellation · Thanks · Something else;
- four emails to rewrite in your own words — Answer to a question, Sorry about that, Before you go, Thank you;
- two automations that read — one for a reply (
email_in), one for a message to your own support inbox (support) — each of which has the model set Intent from what the person wrote; - four automations that draft — each watching Intent, each drafting the matching email for the owner to send. The cancellation one also puts Call <name> today: they are cancelling on the owner's list, due today.
What it costs. One model call per message that arrives, on your workspace's own allowance under Settings → Billing. The four drafters ask nothing at all: they read a field. A workspace with AI switched off installs the whole starter happily and the two readers are skipped with a sentence in the run's log, which the activation question tells you before you arm one.
What it never does. There is no send_email anywhere in it. Every card says drafts only.
Why it is six automations and not one. Otherwise is one level, on purpose: four outcomes
cannot be one sentence without becoming a flowchart. One classifier and four drafters also means
each card is a line you can read and switch on by itself, and only the first one spends anything.
2. The morning brief
Switch it on: Settings → General → What Kicklace does on its own → A morning brief. Get it by email: your own profile, one tick box per workspace.
At 08:00 in the workspace's own timezone, once a day, Kicklace works out what changed in the last twenty-four hours and, if there is anything to say, delivers one notice.
What it counts, all from the database:
| Line | What it means |
|---|---|
| 3 people joined: … | People who left an address, whose first touch was in the last day (or, for a record typed in by hand, the day it was made) |
| 2 people have gone quiet after 14 days: … | People who left an address, whose last activity crossed the fortnight line in the last day — so a person is named the morning they go quiet, and not every morning after |
| 2 proposals are waiting for you: … | Pending approvals (#211) that have not run out |
| 4 emails and 1 broadcast are drafted and waiting to be sent | Open tasks an automation left with draft_email, and broadcast drafts |
| Subscribers this month: 41 — 33 the period before (+24%) | Every number tile on the main dashboard that compares itself against the period before and moved |
Joined and went quiet name only people who left an address — the same line the People view draws. A browser that read a page and went away again is on the visitors chart, and five Anonymous visitor rows every morning would be noise nobody can act on.
When it actually arrives. The worker runs on Vercel Cron and after a page loads. The worker's cron runs every hour (since 2026-09-09, on the Pro plan), so a brief for this morning's 08:00 lands within the hour — sooner if anyone opens a page, since a page load looks too. The occurrence it covers is the calendar's, not the worker's, so a late brief is still yesterday-to-08:00 and it is never written twice.
Then, only if AI is on, one model call (purpose brief, on the same allowance) writes at most
two sentences over the top of those facts. The model is shown the facts and nothing else, and it
is told never to state a number or a name it was not given. The facts go out whether or not it
answers: a model that is down, a switch that is off, or a day's allowance already spent all mean
the brief arrives with no lead sentence and every fact intact.
Where it lands: the bell, for every owner and admin; your Slack channel, because it goes
through notifyManagers like every other notice; and, by email, to each manager who ticked the
box on their profile.
A workspace with nothing to say gets nothing. "Nothing new" is not news, and a bell that is empty six mornings out of seven is a thing people switch off.
Stopping the email. Every brief carries a Stop the brief link. It is signed the way a reply address is, so one click works straight from the email with no sign-in — and it takes you off that workspace's email and nothing else: the brief stays on for everybody, and it is still in your bell.
3. What Kicklace notices
Switch them on: Settings → General → What Kicklace does on its own → What Kicklace notices. Each is one sentence with its own box; none is on by default.
| Rule | What it looks for |
|---|---|
| Read your pricing twice | People who read a page with "pricing" in its address twice in the last seven days, have an email address, and have never had an email from you |
| Signed up and never got started | People who made an account seven days ago or more and have not been activated since |
| Cancelled and nobody wrote back | People whose subscription was cancelled in the last seven days and who have had no email from you since |
| A reply nobody answered | People who wrote to you more than two days ago and have had nothing back |
Each runs once a day, at the same 08:00 the brief lands, and each is plain SQL over your own timeline. Nothing here calls the model.
When a rule finds somebody it writes:
- one notification — "3 people read your pricing page twice this week and have never heard from you: Ada Lovelace, Grace Hopper and Alan Turing" — with the names capped at five;
- one task per person (at most ten a day) on that person's record, for the workspace's first owner, due today, written by what Kicklace noticed. It never writes the same task twice: a person already on your list is left there.
Where the workspace has the email for it — the one the Reply triage or SaaS starter installs — the notice names it as the wording to start from, and a rule that found exactly one person links straight to the composer with those words in it.
A rule that finds nobody says nothing at all.
4. Autonomy, granted per sentence
From docs/ai-centric-direction.md §10: autonomy is granted per sentence, never per agent. So
every automation and every starter wears one of three words, worked out from what it actually does
and whether it is switched on — never written by hand, so it cannot say one thing while the
definition does another.
| Word | When | What it means |
|---|---|---|
| drafts only | Nothing in it emails a person | What it writes waits for a person to send it |
| proposes, you approve | It emails people, and it is not switched on | Activating it is your approval; until then nothing goes out |
| runs alone | It emails people, and it is on | It emails people without asking again |
The word is on the automation's own card, in the automations list beside its state, and on every
starter in Settings → Setup. send_email is the one act that counts as reaching outside: a Slack
line, a signed post to your own server and an email to a member all stay inside the team.
5. What it never does
- It never sends an email to a customer. Not the brief, not a noticing rule, not any part of
Reply triage. The one thing in Kicklace that emails a person because a rule said so is a
send_emailyou switched on yourself. - It never deletes anything, and it never changes a setting.
- It never puts anybody on a list.
- The model never sees another workspace, another record, or a timeline row's words except the
message that started the run — the same rule every AI step keeps (
docs/automations-v2.md→ The four that ask the model). - It never spends without the switch. The brief's lead and Reply triage's classifier both go
through
askModel: the server's key, the workspace's AI switch, the account's daily allowance, and the meter the console reads. Everything else here asks nothing.
6. Where it lives
| Piece | File |
|---|---|
| The brief's facts, and the words they become | src/lib/data/brief.ts |
| The hour, the lead, the delivery, the claim | src/lib/automation/brief.ts |
| The signed "Stop the brief" address | src/lib/automation/brief-token.ts, src/app/brief/stop/[token]/ |
| The four rules | src/lib/automation/noticing.ts |
| Both jobs in the worker | src/lib/automation/tick.ts |
| The switches | src/components/settings/features-form.tsx → AgentForm |
| The email opt-in | src/components/account/brief-email.tsx |
| The three words | src/components/automations/describe.ts → autonomyWord |
| The starter | blueprints/reply-triage.json |
Both daily jobs are claimed per workspace through a jobs row (brief:<id>, notice:<id>), one
update … where last_run_at < … returning, so two checks running at the same moment cannot both
write a brief. There is no migration behind any of it: the two new notification kinds and the
new features keys are a text column and a jsonb one.
Tests: src/lib/data/__tests__/brief.test.ts, src/lib/data/__tests__/noticing.test.ts, the
three words in src/components/automations/describe.test.ts, and the starter in
src/lib/data/__tests__/blueprints.test.ts.