Repository navigation
automations: replace standing orders with reminders, scheduled work and watches - #1831
Merged
Merged
Conversation
The design (docs/design/automations/DESIGN.md) replaces standing items and the v1 scheduler with one mechanism: a schedule, an optional look, an action, run only while a codeaf window is open. audit-notes/standing-and-schedules.md is the evidence it answers. internal/automation is the object and its machinery, with nothing wired yet: - schedule: five-field cron read in the automation's own zone, stepping in absolute time so the wall clock never goes backwards (a 01:30 line runs once on the night the clocks fall back); intervals on an anchored grid, so late runs never drift the next one; lines that never match are refused. - store: SQLite (WAL) with the person's half as a document and the clock's state as guarded columns; a slot becomes a run in one transaction and can never be taken twice; a change counter every window reads from. - presence: one OS lock per open window, so "is any window open?" is answered by the kernel, not a heartbeat. - clock: one holder at a time, catch-up once and marked late, one run per automation at a time, two pieces of work at once, watches that speak on the change to yes, explicit outcomes read from reports and context causes, and a clean stop when the last window closes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… runner - `automation` (propose, list, pause, resume, delete, run, history) is on a conversation's belt when a store is behind it, and never on a task's or a run's: nothing an automation does may arm another. Every answer ends with the time. - The card is one question kind (`automation`) built once in the session: 1 Save · 2 Save and run it now / check it now (not for reminders or worktree work) · 0 Don't save · words are a correction. It shows the schedule in words and exactly, the first run, and a watch's estimated daily cost when the price is known. Save and run it now hands the action back to do in this turn, so approvals reach the person and "always" is banked for later runs. - The runner looks (a command with the provider keys stripped, a bounded file listing that says what changed since the last decided look, or a tool through the person's own gate with its connected account put to use first), judges every look on the low-tier seat and bills it to the usage ledger against the automation, and runs work as a session built from the person's own config: their approval rules with nobody to ask, the first refusal for want of the person stopping the run as your call, a money cap, and an outcome that comes only from `automation_report`. - File watches keep a small memo between looks so a change made while codeaf was closed is still seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A memories column, always_on, declared for new stores and added to old ones by migrateMemoriesAlways inside one immediate transaction, with a partial index over active rules; the owner migration now checks its column inside its transaction too, so two opens of one old store at once cannot both alter the table. - memory_always events set and clear the flag; the add and supersede payloads carry it, a supersession keeps the retired row's rule, and the replay and the sync fold both apply it. - The write door promotes a remembered row when the same words are asked for always, and never demotes a rule. - AlwaysMemories reads the rules for named owners in one order (person, machine, project; oldest first); rules are no longer router candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… machine - `codeaf clock` (hidden machinery, like `engine`) is the one process that runs automations: it takes the lock or leaves, builds each run's configuration through the same assembly a conversation uses (extracted from openV3Launch as v3ConfigFor, which finds no conversation and starts nothing), runs keyless when there is no key so reminders still work, and retires when its binary is replaced and nothing is running. - Every window holds presence for as long as runSurface runs and starts a clock when none holds the lock, checking again every 30s. - Conversations get the automations door, one store handle per process. - Every start of this build takes the old launchd/systemd timers (tick and wake, both names) off the login, acting only on definition files it finds under HOME. `codeaf tick` stays as a hidden verb that does nothing, so a timer an older build installed ends quietly until it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and the store watcher Every window reads the automations store on a two-second beat: a finished run draws one dim line in the conversation that made it, the first window on the machine to claim a run raises the desktop notification, and the quit question gets its snapshot. Local windows hold presence themselves; the doors to another machine will hold it there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ace's a - Session: remember gains always; a rule settles through the one write path and lands as a preference; an ordinary line never sees, rewords or retires a rule; /always (RememberAlways) asks nothing; AlwaysMemories lists the rules in force; a conversation with no project of its own keeps its rules for the person and says so. - The model's own rule is a question: internal/approval's KeepsARule is a floor under every allow (and under no policy at all), no memo or guardian answers it, its card offers no standing yes, and with nobody to ask it is refused in words the model can act on. - Injection beside the standing orders: an <always> block in message[0] (no ages, stable order, 12 rules / 2,400 runes, kept on a failed read, lean profiles included), task briefs, plan-born run workers and codeaf do; rules skip the binding reads and the memory tidy. - Wire: Memory.RememberAlways, Memory.Always and Memory.SetAlways. - TUI: /always and its listing, an always fact on rule rows, a on the strip and the foot, and the card. - Manual: three sections on what-i-remember and the probes that ask how to make a rule; PERF.md records the rules block's bounds. - The fixed prefix is over its cap by 152 bytes on this branch alone; the waivers are not raised (the standing deletion pays it back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The v1 resident kept a scheduler nothing could reach: no surface has made a charter since #469, and no production code installs its timer. It still ran through `codeaf wake`, advertised in --help as "run one full background pass by hand", and doctor read its timer. docs/design/automations/DESIGN.md replaces all of it; this removes it. Gone: - internal/resident: the watch engine and sentinel seam (watch.go), charter commands and the timer offer (charters.go), tenure, the practice loop, the retrospective's charter proposals and hygiene nudges, and every hook in the tick, the quiet gate and the splice (the charter draft on compile). - internal/store: charter.go, charter_spec.go, tenure.go, standing_watch.go, the practice loop's half of practice.go and the dead notebook reads, the charter command kinds, the proposal-appetite trait and the "proposals" reversal class, and the three charter question categories. - internal/head: the temporal compiler (standing.go), the charter half of question answering (charters.go, now answers.go), rule targets in change/stop/recall/open/status, the `standing` belt read, and the money rails for standing proposals. - internal/watchdog, and internal/registry (no importers at all). - cmd/codeaf: wake's pass, the sentinel client, the doctor rows `background timer` and `standing`, and the wiring in resident_build.go. - config: practice_budget_usd, practice_idle, brief_after and tenure_after, their rows, resolvers and env-table lines; the keys are retired, so a profile holding one is not told it is ignored. `codeaf wake` stays dispatched as a hidden verb that does nothing and exits 0, because a timer an older build installed keeps running it until the first start of the automations build removes it, and an unknown verb exits 1. Old stores still open and rebuild. Every v1 event stays in the journal and replays as an unknown kind; the `charters` table is no longer created but is never dropped, and nothing reads it beyond a tolerant lookup naming an older build's work in a self receipt. nodes.charter_id, Provenance.CharterID, agent_questions.origin_charter_id, the brief's charter item and the practice rounds' question replay all stay, because removing them is a migration that says nothing new. A charter question an older build left open lapses on the next pass, and a queued charter command is refused in a sentence rather than by its spelling. internal/store/legacy_scheduler_test.go pins both halves. The resident's own manual loses standing-goals.md and says what happened in daily-rhythm.md; the chat manual's `codeaf wake` section becomes one short section with `codeaf tick`, and the doctor section loses its timer row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re, and its clock kept for an attached window A window over --host or --at sits in front of a conversation on another machine, whose automation tool saves into that machine's store and whose clock runs only while a window is open there. So such a window now reads and changes the far machine's automations, and the far clock counts it. - Protocol 21: thirteen Automations.* calls, one per tui3.AutomationsSeam function, answered from the engine machine's store; Welcome.Automations and Welcome.AutomationsZone say the engine has them and in which zone a rhythm is read; Hello.Window says the connection is a window. - The engine door supplies remote.EngineAutomations (the store, the zone, and keepAutomationsWindow as HoldWindow). A Window hello holds presence before it is welcomed and lets it go on every road out; an engine with no store advertises nothing and refuses every call. - hostOptions builds the seam from the client when the welcome says so, and the zero seam otherwise. Only the --host and --at boot dials say Window; the beside dials and the local engine road never do, which a structural law now holds. - Manual: a section on which machine runs them and when they stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/STANDING.md opens with a note saying what was removed, what an older store keeps, and that docs/design/automations/DESIGN.md replaces it; the rest of the page is left as history. docs/FEATURES.md loses the entries that described the removed machinery as working: the timer offer, charter proposals, the practice loop, probation and tenure, and `codeaf wake`. The entries that only mentioned it (the modality rail, the retrospective, the arrival brief, curiosity receipts, competence, doctor and the environment list) now say what the code does. docs/LIMITS.md drops the practice carve-out row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cmd/codeaf-demo-home now makes seven automations across its three projects (two reminders, the morning sweep on a cron line, a dependency bump in a separate worktree, a command watch on CI, a once-watch on pricing.json, and a paused one) and replays the clock over a fortnight of open windows, so their runs carry every outcome, late catch-ups, and run folders that are really on disk. Three were said in seeded conversations, whose Words are turns those journals have, so their lines land when those conversations open. The spend ledger books each run's own cost under UsageLine.Automation in place of the standing check line, and the package no longer imports internal/standing. internal/automation gains Store.SetClock: the one door a fixture needs to write a history through Create, Take, Start and Finish at the moment it happened. Nothing in the product calls it. A demo launch, and the hand-open line it prints, set CODEAF_NO_AUTOMATIONS=1, so no window opened on the demo starts the clock: the seeded work would otherwise run for real on the person's own key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing leaves tui3 /automations replaces the standing place in the same slot: the list with each automation's schedule and last run, its history, and → run, pause, stop, edit, delete and open. The exact typed forms add, edit, run, pause, resume and delete, and an add or edit ends on a card like the model's. Leaving the last window with a run in hand warns once. Home's next panel and since-you-left read automations; ask here keeps working, re-homed to its own errands folder, with the automation card in its pane. Every standing surface in tui3 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-cron-system-7b4f2b # Conflicts: # cmd/codeaf/chatv3_host.go
…eaf-cron-system-7b4f2b
…nt95/codeaf-cron-system-7b4f2b # Conflicts: # cmd/codeaf/beltdoors_test.go # internal/manual/chat/running-from-the-terminal.md # internal/tui3/settings.go # internal/tui3/settingspend.go
…/codeaf-cron-system-7b4f2b
…e the place prose Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e wire - internal/session: the stand tool, its card, inbox, world section, mark and runner are deleted; the belt fact and the page's paragraph now name `automation`, and the prefix waivers fall to the measurement - automation runs borrow the brain read-only, as standing firings did - the memory tidy rides the clock (automation.Tidy), gated on MachineIdle - the sweep's fourth rule reaps stale errands and keeps any an automation was saved from - an automation card answered from another window takes every key its own card drew (`2` was refused at the doorstep) - cmd/codeaf: the ticker, the background repair, the standing seam and the host's standing cache are gone; the clock carries the tidy - remote: Standing.* methods, ResolveStanding and the marked submit leave the wire; the held kind goes; the surface-door ledger drops to 18 - config: the background-checks row is retired with its key - run: worker briefs close on the person's rules alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- `watch`'s description said lasting checks were `stand`'s, a tool that is gone; it now names an automation without naming a verb some belts lack - the unused standing-check call purpose leaves; the replay tool still reads old logs that carry it - the fixed prefix falls another 8 bytes and its waiver with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- the design doc gains the typed grammar, the → keys, the quit warning as shipped, the store's notification claim, the kept `ask here` errands, the read-only brain and the tidy on the clock; the watch cost estimate it promised was never built and goes - the guide, the README, FEATURES, LIMITS and the memory docs name automations and `/always` where they named standing orders; the README's standing screenshot goes with the page it showed - AMBIENT and STANDING-ORDERS are marked superseded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing in internal/e2e imports internal/standing or leans on a standing door any more, so the package builds once those are deleted. - The host guard proves the old-timer removal touches only the throwaway login: testdata/oldtimers runs RemoveOldTimers as a real program behind the guard, and the developer's tick and wake files, both names, are hashed around it. The guard also stands in for osascript and notify-send, and sets CODEAF_NO_AUTOMATIONS=1 on every launch whose scenario does not name it. - The shared world keeps no ambient store and no standing answers; say and drain take none, and decline an automation card if one ever comes. - The three standing lanes are deleted. TestAutomationsE2E replaces the three TestTUIE2E subtests that were about standing orders, with no key: ask here ending on an automation card (wide and narrow), and a typed reminder said by the clock into its conversation, as a notification and on the automations place, then the clock leaving on its own. - The words table drops the standing rows, respells the ones automations renamed, and catches up with home's activity heading, the seven-place bar and the Spending tab's per-chat label; testHomeShape, testAnswerFromHome and testOneSpendFigure read what is drawn now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three test files still named what the standing removal took away, so neither package's tests built at this commit and no manual gate in them could run: notice_test.go proved a retirement event that no longer exists, and the usage tests asked for a spend subject that is now SubjectAutomation. - notice_test.go: the gesture is /automations, which fires eventAutomationsOpened. - usage_ledger_test.go: an automation's run writes its line under the automation's id, and the rollup names the automation. - usage_spend_test.go: the automation row and its subject word. These are byte for byte the versions 61022e9 carries, so the two branches agree on them when they meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on-system-7b4f2b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The chat corpus still taught standing orders — /standing, the stand card, keeping an eye, the OS timer and `codeaf tick` — after automations had replaced them. The chat answers from these pages alone, so it would have offered a page, a key and a timer that no longer exist. - automations.md is new: reminders, scheduled work and watches; the card and its answers; schedules and cron; /automations and its → verbs; history and what a run came to; where the news arrives; the clock that runs only while a window is open, missed runs marked late; cost limits; worktree or checkout; the typed /automations forms; ask here; rules as memories marked always; the automation and automation_report tools; where standing orders went; and what automations cannot do. - keeping-an-eye.md and standing-orders.md are deleted. Every other page that described standing — home, keys, commands, places, screen, asking-from-home, the remote pages, models-and-cost, questions, tasks, what-i-can-do, what-i-remember, hints-and-tips and the rest — now says what the automations code does, quoting its strings. - chat_test.go: the forty-nine probes that reached a deleted page are pointed at the page that answers them now, and fifty-six probes are added in the asker's words. The rerun and due-time tests follow. - truth_test.go no longer imports internal/standing: the standing facts leave, and automation.DefaultTime and automation.DefaultUSD are pinned where the pages quote them. - asked.go's wants follow the pages; lawregistry_test.go drops the two laws filed against keeping-an-eye; session's manual gate opens an automations store so `automation` is checked, and a second gate builds a run's belt so `automation_report` is too. - The e2e due-time subtest still reaches home, and waits for the sentence that says where an automation's next time is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-cron-system-7b4f2b Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> # Conflicts: # internal/e2e/manual_e2e_test.go
Nothing imports it any more: the session, the doors, the wire, the config, the manual's truth table and the end-to-end suite have all moved to internal/automation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A home tip says a key or a command first, and the one that taught saying an automation did not, so home's row broke its own law. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The kind names nothing codeaf runs any more. A row an older build wrote can still be found and taken out; the schema keeps the kind so an older build on the same machine still opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The missed runs were gathered only on a window's first reading, so a conversation switched to in a window already open never heard them. Now any conversation that comes to the front is asked about once, and a run a window has drawn is not drawn twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The ratchet walked the standing ticker and inbox, which are gone; it now walks the automations clock, store and runner. The run's Work held 25 decisions against a ceiling of 15, so it is split along its own phases: the run's configuration, the turn watched for the two reasons to stop, and what it came to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments in cmd/ and internal/ (internal/standing and internal/e2e left alone) that still described the standing feature as current now say what the code does: the automation tool, /automations, `codeaf clock` and the rules marked always. Historical records are kept, with doc links to deleted symbols turned into plain text or pointed at the replacement, and every bracketed link a rewritten comment names resolves. Comments only: the token stream of every changed file is identical outside comments, apart from one stray blank line in effortscope.go's import block that gofmt removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Standing firings were held to the person's daily limit; an automation's work run is shaped like a task, which the turn's check passes over, so it spent past the limit. It now asks before anything is made for it and reads `your call` when the limit is reached. A watch's looks are not held to it: each costs a fraction of a cent, and a refused look is news. The design doc gets back the watch cost estimate, which is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- home settles its phone shape before it builds again; the band read that used to do it went with standing orders - `/automations` has its fates on home: the place bare, a conversation for `add` and `edit`, home's own line for the id verbs - `automation_report` is communication, and both automation tools have a folder-hold disposition; `usd` is a fractional argument - the dead standing fields, the backlog fold, the held kind, a separator and three band orders are removed - tests that still named standing words, `/standing` as a door or the standing ladder stamper now read the automations surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…7b4f2b An approval raised inside an ask-here errand is now asked in its own pane, so a rule the model proposes from home no longer leaves the row stuck on working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A place that appeared only while somebody stood in it was a room nobody knew was there. Eight words need 84 columns, so a narrower frame folds spend and settings behind more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s find the key What the owner's walkthrough of the first build found, fixed: - A banner is raised whether or not codeaf has the keyboard, so `r` on a reminder raises one too. In iTerm2 it is iTerm2's own (OSC 9), in Ghostty, kitty, WezTerm and foot the terminal's OSC 777, and clicking it brings the tab back. Elsewhere it is osascript with a sound, or notify-send with the logo. The first banner on a machine names the sending app once, linked to Notification settings. A codeaf-branded macOS banner needs a Developer ID: macOS 26 refuses an ad-hoc-signed applet silently. - A run's line is also said on the message line of home or the place in front. - Quitting never asks. A run closing codeaf cut off is told to nobody and runs again, once, when a window next opens. - A watch's check passes over a model whose service has no key, down to the conversation's own model, and names the model and service when none is reachable. The clock re-reads the saved key before every run, and follows the newest window's environment (a salted fingerprint, never a value), so a key exported in one shell and not another no longer decides it. - The typed form reads `at 6pm`, `at tomorrow 9am` and `at monday 9am` without quotes. - The clock no longer runs the memory tidy, which the memory rework rules out. - Home's since-you-left whisper no longer says watches run while codeaf is shut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e row-zero law starts at 84 columns A run codeaf closing cut off now picks up again, which the demo's replay of the rhythm cannot express. Eight words on the bar need 84 columns, so that is where the bar is promised never to move. The since-you-left whisper says what happened rather than what landed, which a first look must not claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n-system-7b4f2b # Conflicts: # internal/tui3/switcher.go
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4 tasks done
…ner carries it The run under the cursor in an automation's history shows its full report in ordinary text, and the history opens on the newest run. A banner says what the run came to and up to 180 characters of its report, without repeating the title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 14, 2026
- Deleting an automation stops its run in hand: the clock asks whether each run's automation still exists, since the delete takes the run rows (and any stop request) with it. - A rhythm of days that would overflow a duration is refused, not wrapped. - A files watch's walk checks its budget and its run's context on every entry, so a rarely matching glob over a whole home no longer walks it all. - The judge's client is kept per model and account, so a replaced key is used. - A window's presence file is locked and written before it is renamed into place, so a counter can no longer remove a window being opened. - `codeaf do` reads the rules before its deadline starts. - A typed id needs four characters, and the refusal says where the id comes from. A ~ folder crosses unexpanded and the store reads it as its own machine's home, so a line typed over --host names the far machine's folder. - Each automation keeps its last hundred runs; forgotten and deleted runs' folders go, except a folder holding a worktree, whose changes are the person's to review. - A watch's banner says its own line, not what its look saw. - The old timers' files are removed before their jobs are unloaded, by label. - Stale docs and comments; the audit note is dropped from the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ZeroPoint95
marked this pull request as ready for review
October 14, 2026 21:56
…n-system-7b4f2b # Conflicts: # internal/manual/chat/asking-from-home.md # internal/manual/chat_test.go # internal/tui3/homeexchange.go # internal/tui3/homeexchange_consent_test.go # internal/tui3/homeexchange_test.go
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n-system-7b4f2b # Conflicts: # internal/e2e/tmux_test.go # internal/manual/chat/asking-from-home.md # internal/manual/chat/commands.md # internal/manual/chat/home.md # internal/manual/chat/keys.md # internal/manual/chat/places.md # internal/manual/chat/screen.md # internal/tui3/home.go # internal/tui3/homeexchange.go # internal/tui3/homephone_test.go
ZeroPoint95
added a commit
that referenced
this pull request
Oct 15, 2026
dev's new commit is #1831's squash, whose tree is exactly aa30148, which this branch already merged. The merge base predates it, so every region the memory work edited on top of automations reported a conflict; each resolves to this branch's side, and the result is this branch's tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ZeroPoint95
added a commit
that referenced
this pull request
Oct 15, 2026
…r silently (#1830) * automations: the design, and the core — schedule, store, presence, clock The design (docs/design/automations/DESIGN.md) replaces standing items and the v1 scheduler with one mechanism: a schedule, an optional look, an action, run only while a codeaf window is open. audit-notes/standing-and-schedules.md is the evidence it answers. internal/automation is the object and its machinery, with nothing wired yet: - schedule: five-field cron read in the automation's own zone, stepping in absolute time so the wall clock never goes backwards (a 01:30 line runs once on the night the clocks fall back); intervals on an anchored grid, so late runs never drift the next one; lines that never match are refused. - store: SQLite (WAL) with the person's half as a document and the clock's state as guarded columns; a slot becomes a run in one transaction and can never be taken twice; a change counter every window reads from. - presence: one OS lock per open window, so "is any window open?" is answered by the kernel, not a heartbeat. - clock: one holder at a time, catch-up once and marked late, one run per automation at a time, two pieces of work at once, watches that speak on the change to yes, explicit outcomes read from reports and context causes, and a clean stop when the last window closes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the engine side — the automation tool, its card, and the runner - `automation` (propose, list, pause, resume, delete, run, history) is on a conversation's belt when a store is behind it, and never on a task's or a run's: nothing an automation does may arm another. Every answer ends with the time. - The card is one question kind (`automation`) built once in the session: 1 Save · 2 Save and run it now / check it now (not for reminders or worktree work) · 0 Don't save · words are a correction. It shows the schedule in words and exactly, the first run, and a watch's estimated daily cost when the price is known. Save and run it now hands the action back to do in this turn, so approvals reach the person and "always" is banked for later runs. - The runner looks (a command with the provider keys stripped, a bounded file listing that says what changed since the last decided look, or a tool through the person's own gate with its connected account put to use first), judges every look on the low-tier seat and bills it to the usage ledger against the automation, and runs work as a session built from the person's own config: their approval rules with nobody to ask, the first refusal for want of the person stopping the run as your call, a money cap, and an outcome that comes only from `automation_report`. - File watches keep a small memo between looks so a change made while codeaf was closed is still seen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: the store keeps rules as memories marked always - A memories column, always_on, declared for new stores and added to old ones by migrateMemoriesAlways inside one immediate transaction, with a partial index over active rules; the owner migration now checks its column inside its transaction too, so two opens of one old store at once cannot both alter the table. - memory_always events set and clear the flag; the add and supersede payloads carry it, a supersession keeps the retired row's rule, and the replay and the sync fold both apply it. - The write door promotes a remembered row when the same words are asked for always, and never demotes a rule. - AlwaysMemories reads the rules for named owners in one order (person, machine, project; oldest first); rules are no longer router candidates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the clock process, window presence, and no timers on the machine - `codeaf clock` (hidden machinery, like `engine`) is the one process that runs automations: it takes the lock or leaves, builds each run's configuration through the same assembly a conversation uses (extracted from openV3Launch as v3ConfigFor, which finds no conversation and starts nothing), runs keyless when there is no key so reminders still work, and retires when its binary is replaced and nothing is running. - Every window holds presence for as long as runSurface runs and starts a clock when none holds the lock, checking again every 30s. - Conversations get the automations door, one store handle per process. - Every start of this build takes the old launchd/systemd timers (tick and wake, both names) off the login, acting only on definition files it finds under HOME. `codeaf tick` stays as a hidden verb that does nothing, so a timer an older build installed ends quietly until it is removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the window side — the card, the run lines, notifications and the store watcher Every window reads the automations store on a two-second beat: a finished run draws one dim line in the conversation that made it, the first window on the machine to claim a run raises the desktop notification, and the quit question gets its snapshot. Local windows hold presence themselves; the doors to another machine will hold it there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory always: rules ride every turn and task, /always, the memory place's a - Session: remember gains always; a rule settles through the one write path and lands as a preference; an ordinary line never sees, rewords or retires a rule; /always (RememberAlways) asks nothing; AlwaysMemories lists the rules in force; a conversation with no project of its own keeps its rules for the person and says so. - The model's own rule is a question: internal/approval's KeepsARule is a floor under every allow (and under no policy at all), no memo or guardian answers it, its card offers no standing yes, and with nobody to ask it is refused in words the model can act on. - Injection beside the standing orders: an <always> block in message[0] (no ages, stable order, 12 rules / 2,400 runes, kept on a failed read, lean profiles included), task briefs, plan-born run workers and codeaf do; rules skip the binding reads and the memory tidy. - Wire: Memory.RememberAlways, Memory.Always and Memory.SetAlways. - TUI: /always and its listing, an always fact on rule rows, a on the strip and the foot, and the card. - Manual: three sections on what-i-remember and the probes that ask how to make a rule; PERF.md records the rules block's bounds. - The fixed prefix is over its cap by 152 bytes on this branch alone; the waivers are not raised (the standing deletion pays it back). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: delete the v1 resident's scheduler The v1 resident kept a scheduler nothing could reach: no surface has made a charter since #469, and no production code installs its timer. It still ran through `codeaf wake`, advertised in --help as "run one full background pass by hand", and doctor read its timer. docs/design/automations/DESIGN.md replaces all of it; this removes it. Gone: - internal/resident: the watch engine and sentinel seam (watch.go), charter commands and the timer offer (charters.go), tenure, the practice loop, the retrospective's charter proposals and hygiene nudges, and every hook in the tick, the quiet gate and the splice (the charter draft on compile). - internal/store: charter.go, charter_spec.go, tenure.go, standing_watch.go, the practice loop's half of practice.go and the dead notebook reads, the charter command kinds, the proposal-appetite trait and the "proposals" reversal class, and the three charter question categories. - internal/head: the temporal compiler (standing.go), the charter half of question answering (charters.go, now answers.go), rule targets in change/stop/recall/open/status, the `standing` belt read, and the money rails for standing proposals. - internal/watchdog, and internal/registry (no importers at all). - cmd/codeaf: wake's pass, the sentinel client, the doctor rows `background timer` and `standing`, and the wiring in resident_build.go. - config: practice_budget_usd, practice_idle, brief_after and tenure_after, their rows, resolvers and env-table lines; the keys are retired, so a profile holding one is not told it is ignored. `codeaf wake` stays dispatched as a hidden verb that does nothing and exits 0, because a timer an older build installed keeps running it until the first start of the automations build removes it, and an unknown verb exits 1. Old stores still open and rebuild. Every v1 event stays in the journal and replays as an unknown kind; the `charters` table is no longer created but is never dropped, and nothing reads it beyond a tolerant lookup naming an older build's work in a self receipt. nodes.charter_id, Provenance.CharterID, agent_questions.origin_charter_id, the brief's charter item and the practice rounds' question replay all stay, because removing them is a migration that says nothing new. A charter question an older build left open lapses on the next pass, and a queued charter command is refused in a sentence rather than by its spelling. internal/store/legacy_scheduler_test.go pins both halves. The resident's own manual loses standing-goals.md and says what happened in daily-rhythm.md; the chat manual's `codeaf wake` section becomes one short section with `codeaf tick`, and the doctor section loses its timer row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: over --host and --at — the far machine's store on the wire, and its clock kept for an attached window A window over --host or --at sits in front of a conversation on another machine, whose automation tool saves into that machine's store and whose clock runs only while a window is open there. So such a window now reads and changes the far machine's automations, and the far clock counts it. - Protocol 21: thirteen Automations.* calls, one per tui3.AutomationsSeam function, answered from the engine machine's store; Welcome.Automations and Welcome.AutomationsZone say the engine has them and in which zone a rhythm is read; Hello.Window says the connection is a window. - The engine door supplies remote.EngineAutomations (the store, the zone, and keepAutomationsWindow as HoldWindow). A Window hello holds presence before it is welcomed and lets it go on every road out; an engine with no store advertises nothing and refuses every call. - hostOptions builds the seam from the client when the welcome says so, and the zero seam otherwise. Only the --host and --at boot dials say Window; the beside dials and the local engine road never do, which a structural law now holds. - Manual: a section on which machine runs them and when they stop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the v1 scheduler is gone docs/STANDING.md opens with a note saying what was removed, what an older store keeps, and that docs/design/automations/DESIGN.md replaces it; the rest of the page is left as history. docs/FEATURES.md loses the entries that described the removed machinery as working: the timer offer, charter proposals, the practice loop, probation and tenure, and `codeaf wake`. The entries that only mentioned it (the modality rail, the retrospective, the arrival brief, curiosity receipts, competence, doctor and the environment list) now say what the code does. docs/LIMITS.md drops the practice carve-out row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo home seeds automations, not standing orders cmd/codeaf-demo-home now makes seven automations across its three projects (two reminders, the morning sweep on a cron line, a dependency bump in a separate worktree, a command watch on CI, a once-watch on pricing.json, and a paused one) and replays the clock over a fortnight of open windows, so their runs carry every outcome, late catch-ups, and run folders that are really on disk. Three were said in seeded conversations, whose Words are turns those journals have, so their lines land when those conversations open. The spend ledger books each run's own cost under UsageLine.Automation in place of the standing check line, and the package no longer imports internal/standing. internal/automation gains Store.SetClock: the one door a fixture needs to write a history through Create, Take, Start and Finish at the moment it happened. Nothing in the product calls it. A demo launch, and the hand-open line it prints, set CODEAF_NO_AUTOMATIONS=1, so no window opened on the demo starts the clock: the seeded work would otherwise run for real on the person's own key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the place, the typed command and the quit warning; standing leaves tui3 /automations replaces the standing place in the same slot: the list with each automation's schedule and last run, its history, and → run, pause, stop, edit, delete and open. The exact typed forms add, edit, run, pause, resume and delete, and an add or edit ends on a card like the model's. Leaving the last window with a run in hand warns once. Home's next panel and since-you-left read automations; ask here keeps working, re-homed to its own errands folder, with the automation card in its pane. Every standing surface in tui3 is gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the hints teach automations, and the standing words leave the place prose Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the standing engine leaves the session, the doors and the wire - internal/session: the stand tool, its card, inbox, world section, mark and runner are deleted; the belt fact and the page's paragraph now name `automation`, and the prefix waivers fall to the measurement - automation runs borrow the brain read-only, as standing firings did - the memory tidy rides the clock (automation.Tidy), gated on MachineIdle - the sweep's fourth rule reaps stale errands and keeps any an automation was saved from - an automation card answered from another window takes every key its own card drew (`2` was refused at the doorstep) - cmd/codeaf: the ticker, the background repair, the standing seam and the host's standing cache are gone; the clock carries the tidy - remote: Standing.* methods, ResolveStanding and the marked submit leave the wire; the held kind goes; the surface-door ledger drops to 18 - config: the background-checks row is retired with its key - run: worker briefs close on the person's rules alone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: watch names the idea, and the standing purpose goes - `watch`'s description said lasting checks were `stand`'s, a tool that is gone; it now names an automation without naming a verb some belts lack - the unused standing-check call purpose leaves; the replay tool still reads old logs that carry it - the fixed prefix falls another 8 bytes and its waiver with it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the docs say what was built - the design doc gains the typed grammar, the → keys, the quit warning as shipped, the store's notification claim, the kept `ask here` errands, the read-only brain and the tidy on the clock; the watch cost estimate it promised was never built and goes - the guide, the README, FEATURES, LIMITS and the memory docs name automations and `/always` where they named standing orders; the README's standing screenshot goes with the page it showed - AMBIENT and STANDING-ORDERS are marked superseded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the kind's answer row is said to be the superset it is Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the reading says why it is handed its palette Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * e2e: automations replace standing orders in the end-to-end suite Nothing in internal/e2e imports internal/standing or leans on a standing door any more, so the package builds once those are deleted. - The host guard proves the old-timer removal touches only the throwaway login: testdata/oldtimers runs RemoveOldTimers as a real program behind the guard, and the developer's tick and wake files, both names, are hashed around it. The guard also stands in for osascript and notify-send, and sets CODEAF_NO_AUTOMATIONS=1 on every launch whose scenario does not name it. - The shared world keeps no ambient store and no standing answers; say and drain take none, and decline an automation card if one ever comes. - The three standing lanes are deleted. TestAutomationsE2E replaces the three TestTUIE2E subtests that were about standing orders, with no key: ask here ending on an automation card (wide and narrow), and a typed reminder said by the clock into its conversation, as a notification and on the automations place, then the clock leaving on its own. - The words table drops the standing rows, respells the ones automations renamed, and catches up with home's activity heading, the seven-place bar and the Spending tab's per-chat label; testHomeShape, testAnswerFromHome and testOneSpendFigure read what is drawn now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the tui3 and session test builds compile again Three test files still named what the standing removal took away, so neither package's tests built at this commit and no manual gate in them could run: notice_test.go proved a retirement event that no longer exists, and the usage tests asked for a spend subject that is now SubjectAutomation. - notice_test.go: the gesture is /automations, which fires eventAutomationsOpened. - usage_ledger_test.go: an automation's run writes its line under the automation's id, and the rollup names the automation. - usage_spend_test.go: the automation row and its subject word. These are byte for byte the versions 61022e9 carries, so the two branches agree on them when they meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the e2e timing notes stop promising a standing pass Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the chat manual says what replaced standing orders The chat corpus still taught standing orders — /standing, the stand card, keeping an eye, the OS timer and `codeaf tick` — after automations had replaced them. The chat answers from these pages alone, so it would have offered a page, a key and a timer that no longer exist. - automations.md is new: reminders, scheduled work and watches; the card and its answers; schedules and cron; /automations and its → verbs; history and what a run came to; where the news arrives; the clock that runs only while a window is open, missed runs marked late; cost limits; worktree or checkout; the typed /automations forms; ask here; rules as memories marked always; the automation and automation_report tools; where standing orders went; and what automations cannot do. - keeping-an-eye.md and standing-orders.md are deleted. Every other page that described standing — home, keys, commands, places, screen, asking-from-home, the remote pages, models-and-cost, questions, tasks, what-i-can-do, what-i-remember, hints-and-tips and the rest — now says what the automations code does, quoting its strings. - chat_test.go: the forty-nine probes that reached a deleted page are pointed at the page that answers them now, and fifty-six probes are added in the asker's words. The rerun and due-time tests follow. - truth_test.go no longer imports internal/standing: the standing facts leave, and automation.DefaultTime and automation.DefaultUSD are pinned where the pages quote them. - asked.go's wants follow the pages; lawregistry_test.go drops the two laws filed against keeping-an-eye; session's manual gate opens an automations store so `automation` is checked, and a second gate builds a run's belt so `automation_report` is too. - The e2e due-time subtest still reaches home, and waits for the sentence that says where an automation's next time is shown. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: internal/standing is deleted Nothing imports it any more: the session, the doors, the wire, the config, the manual's truth table and the end-to-end suite have all moved to internal/automation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: home's tip leads with the command A home tip says a key or a command first, and the one that taught saying an automation did not, so home's row broke its own law. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a collection cannot gain a standing item The kind names nothing codeaf runs any more. A row an older build wrote can still be found and taken out; the schema keeps the kind so an older build on the same machine still opens the database. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a conversation switched to is told what it missed The missed runs were gathered only on a window's first reading, so a conversation switched to in a window already open never heard them. Now any conversation that comes to the front is asked about once, and a run a window has drawn is not drawn twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the manual says when an errand that went nowhere is cleared Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: gofmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the complexity ratchet holds the automations engine The ratchet walked the standing ticker and inbox, which are gone; it now walks the automations clock, store and runner. The run's Work held 25 decisions against a ceiling of 15, so it is split along its own phases: the run's configuration, the turn watched for the two reasons to stop, and what it came to. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: comments stop describing standing orders as live Comments in cmd/ and internal/ (internal/standing and internal/e2e left alone) that still described the standing feature as current now say what the code does: the automation tool, /automations, `codeaf clock` and the rules marked always. Historical records are kept, with doc links to deleted symbols turned into plain text or pointed at the replacement, and every bracketed link a rewritten comment names resolves. Comments only: the token stream of every changed file is identical outside comments, apart from one stray blank line in effortscope.go's import block that gofmt removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run of work stops at the daily spending limit Standing firings were held to the person's daily limit; an automation's work run is shaped like a task, which the turn's check passes over, so it spent past the limit. It now asks before anything is made for it and reads `your call` when the limit is reached. A watch's looks are not held to it: each costs a fraction of a cent, and a refused look is news. The design doc gets back the watch cost estimate, which is built. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the suites pass without standing orders - home settles its phone shape before it builds again; the band read that used to do it went with standing orders - `/automations` has its fates on home: the place bare, a conversation for `add` and `edit`, home's own line for the id verbs - `automation_report` is communication, and both automation tools have a folder-hold disposition; `usd` is a fractional argument - the dead standing fields, the backlog fold, the held kind, a separator and three band orders are removed - tests that still named standing words, `/standing` as a door or the standing ladder stamper now read the automations surface Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix: ask an ask-here errand's approvals in its own pane A call inside home's `ask here` errand that the approval policy grades "ask" blocks inside the errand's session until that agent is answered. errandEvent had no case for EventConsentRequest, and nothing else holds the errand's agent, so the errand sat `working` on a question no screen drew, and a `1` pressed at it went into the follow-up box. - The pane now draws the approval under the call it is about, with the conversation's own question builder and renderer: `1 allow once` and `3 deny`. There is no `always` from the pane. - The answer goes straight to the errand's agent (ResolveConsent), not through the block's door, whose receipt lands above the window's own box and whose `c change` would be answered by the window's engine. - The row says `waiting on you` and sorts first; the live block gives way while the turn waits; the call's row keeps `allowed`/`denied`. - The block's settle guard applies to the approval's digits and clicks, so a digit typed into a follow-up cannot allow an unread command. - Approvals are dropped when the turn ends; several in one step are asked oldest first. Results pair to rows by call id. - errandWait is renamed waitErrand so the harness's waiter law sees it and a test can hold a gated stream open. - asking-from-home.md says all of this, and no longer sends approvals to `continue as a conversation`, which ends the waiting call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the word stands on the tab bar, between memory and spend A place that appeared only while somebody stood in it was a room nobody knew was there. Eight words need 84 columns, so a narrower frame folds spend and settings behind more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: one strength, one write door, every line in front of every turn (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: banners through the terminal, closing pauses, and watches find the key What the owner's walkthrough of the first build found, fixed: - A banner is raised whether or not codeaf has the keyboard, so `r` on a reminder raises one too. In iTerm2 it is iTerm2's own (OSC 9), in Ghostty, kitty, WezTerm and foot the terminal's OSC 777, and clicking it brings the tab back. Elsewhere it is osascript with a sound, or notify-send with the logo. The first banner on a machine names the sending app once, linked to Notification settings. A codeaf-branded macOS banner needs a Developer ID: macOS 26 refuses an ad-hoc-signed applet silently. - A run's line is also said on the message line of home or the place in front. - Quitting never asks. A run closing codeaf cut off is told to nobody and runs again, once, when a window next opens. - A watch's check passes over a model whose service has no key, down to the conversation's own model, and names the model and service when none is reachable. The clock re-reads the saved key before every run, and follows the newest window's environment (a salted fingerprint, never a value), so a key exported in one shell and not another no longer decides it. - The typed form reads `at 6pm`, `at tomorrow 9am` and `at monday 9am` without quotes. - The clock no longer runs the memory tidy, which the memory rework rules out. - Home's since-you-left whisper no longer says watches run while codeaf is shut. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the demo's cut-off run is one the person stopped, and the row-zero law starts at 84 columns A run codeaf closing cut off now picks up again, which the demo's replay of the rhythm cannot express. Eight words on the bar need 84 columns, so that is where the bar is promised never to move. The since-you-left whisper says what happened rather than what landed, which a first look must not claim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: store, reflex and session tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: surface tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: wire, door and seeder tests for one strength (WIP) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the tidy, its clock types and the rule-consent floor are gone Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the settings row and the last stale seams match one strength - what-i-remember is rewritten for one strength, the Memory tab, noticing and undo; the other chat pages stop describing the router, the always flag, the tidy, the shelf key and "memory is off" - the settings row is "notice things to remember" and applies from the next turn - the model's forget is seeded allow beside remember: both say what they did and /forget takes it back - a far engine with no store says "memory is unavailable on this machine" - a live switch to the lean profile keeps the memory block - the speed and no-change tests read the noticing pass instead of the removed pre-turn recall and extractor Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the laws, the waivers and the docs follow one strength - lane.RoleRecall goes with the pre-turn recall: a role nobody calls is owed a deletion, and the provider tests that borrowed it use the tool role - the complexity ratchet watches the memory engine instead of the deleted contextual files; learnFromTurn, importMemoryFile and MemorySnapshot split under its ceiling - both prefix waivers fall to the measurement (52,519 and 44,915), in PERF.md too, and PERF.md's memory sections describe the one bounded block - tests that pinned the old shape (lean and tool-less pages dropped memory, an explained override became a memory, the settings row needed a restart) now pin the new one - the settings detail leads with what off does, and "remember across chats" still finds the row - docs/memory-architecture.md describes what memory is now; the contextual page is a pointer into history; the audit that started this is kept Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a test name stops spelling the old product name Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the change entry for #1830 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the change entry for #1831 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: a run's whole result is read in its history, and its banner carries it The run under the cursor in an automation's history shows its full report in ordinary text, and the history opens on the newest run. A banner says what the run came to and up to 180 characters of its report, without repeating the title. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the Memories tab reads like Activity, and /forget is gone - the tab is "Memories"; typing "memory" still finds it, and eight tab words now need 86 columns - groups are rows of their own that open on → and fold on ←, never enter; lines hang on tree connectors with kept-by and age columns, and a pane reads the cursor row out on frames of 110 columns or more - the words being written on the add row or in a line's editor are drawn in that row, with the caret; before, they were typed into nothing visible - /forget and the undo stack behind it are removed: a person forgets and puts back on the tab, the model's forget stays, and every receipt made on the person's behalf says "see or forget it on the Memories tab" - wire Memory.ForgetQuery goes with the command, folded into Version 22 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * automations: the review's fixes - Deleting an automation stops its run in hand: the clock asks whether each run's automation still exists, since the delete takes the run rows (and any stop request) with it. - A rhythm of days that would overflow a duration is refused, not wrapped. - A files watch's walk checks its budget and its run's context on every entry, so a rarely matching glob over a whole home no longer walks it all. - The judge's client is kept per model and account, so a replaced key is used. - A window's presence file is locked and written before it is renamed into place, so a counter can no longer remove a window being opened. - `codeaf do` reads the rules before its deadline starts. - A typed id needs four characters, and the refusal says where the id comes from. A ~ folder crosses unexpanded and the store reads it as its own machine's home, so a line typed over --host names the far machine's folder. - Each automation keeps its last hundred runs; forgotten and deleted runs' folders go, except a folder holding a worktree, whose changes are the person's to review. - A watch's banner says its own line, not what its look saw. - The old timers' files are removed before their jobs are unloaded, by label. - Stale docs and comments; the audit note is dropped from the change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the catalogue test reads the Memories tab row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the bound is the store's, held inside every write Review fixes for #1830. - the 4,800-rune bound, the line cost and the quoting move to the store (memory_room.go); every door that makes a line active — write, replace, reword, move, put back — is measured inside its write transaction against every block the owner reaches, so a line kept everywhere cannot overflow another project, and two writers with room for one admit one - duplicates are the target owner's only; a move or a replacement onto words already kept lets the copy go instead of keeping two, and a forgotten line cannot be moved - a store an earlier build filled past the bound lets its always rules, then project, machine and person lines ride (FitMemories), and the conversation says once how many don't fit - the model's remember and forget act only on a turn the person typed - a noticed line is said on the standing lane when the turn's stream has closed; an ask-here errand is not noticed - memories_fts stays this release for older engines still running - the settings row reads one spelling; the tab's foot over an empty filter says esc; the project lookup's wire error is no longer "no project" - stale comments, names and docs; the audit notes and the contextual doc go Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the guide's tool table names automation, not the removed stand Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: tell a person who had memory off, once per machine, that their lines ride The owner's ruling on R8: on the first start after the upgrade, a person whose memory row was off is told once that their N kept lines now ride every conversation they hold in, with the Memories tab to forget them. The marker is created exclusively beside the store on that first start whatever the setting says, so it is said once per machine and never to someone who turns noticing off later. No line changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a woken turn does not arm the model's verbs; the person's line does A turn a task's landing or a job's ending opens is empty and marked a wake, and it armed remember/forget because it carried no authored mark. The verbs now arm only on a non-empty line the person typed, on their line drained into a turn mid-way, and on the follow-up turn started to answer a line they typed in the last seconds of the turn before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a line noticed while its conversation is out of sight waits for the person The keeper holds a conversation's standing lane while another is on screen, and it drained memory's notices to nowhere. Memory's notices now say they are in no record (Event.Unrecorded); the keeper keeps them, files them with the conversation's parked receipts, and coming back draws them there. A turn's own lines wait for the turn to end, since coming back mid-turn replays them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: a full refusal says whose block it would overflow; an already-kept correction is said The store's refusal now carries the owner it would overflow, and every door says it from the conversation's own view: here, for <project>, or in another project. Over --host the name in the text is compared instead. Noticing a correction that was already kept lets the old line go and now says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: test the bound on replacement, the unbounded import and a held second writer A seam inside the room check holds the first writer in its transaction; the second must not read the room until the first commits, and then finds none. The test fails with deferred transactions. Replacement is measured, and the legacy import is kept whole past the bound. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: words already kept are not put back twice; an unknown project counts nothing Putting back a line, or rewording one, onto words its owner already keeps active is refused with store.ErrMemoryKept, and the tab says "already kept". When the engine cannot say which project this is, the tab takes nothing from the failed answer and its head row draws no don't-fit count. Tests cover the tab's refusal words, the no-match hint and the no-project note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: a stub keeps the changelog's contextual-memory link; its terminal recipe goes CHANGELOG.md links docs/contextual-memory.md, so a one-line page says it is retired and where its contents are. The terminal acceptance recipe and its recorder tested the removed evidence layer, and are deleted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the manual, the change entry and the design say what round two changed Full receipts say whose block; words already kept are refused on put-back and rewording; an already-kept correction is said; a line noticed out of sight waits for the person; a woken turn arms the verbs only once the person types; an unknown project counts nothing that doesn't fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * memory: the turn that answers the person carries it on its own message A stale flag could outlive a failed, declined, vision or abandoned turn and arm the next task's landing. The drain now reports whether it heard the person: mid-turn that arms the rest of the turn, and at the turn's end the follow-up wake's opening carries answersPerson. No agent state is left. A real-loop test fails a turn after a steer and checks the next wake is not armed; the keeper's turn notices, the hand-off on the way forward and the unrecorded mark are each pinned by a test that fails without them. The manual says an answer to a question on an idle conversation does not arm the verbs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs: the change entry records the re-measured prefix waivers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces standing orders with automations: reminders, scheduled work and watches that run while a codeaf window is open.
What changed
internal/automation, with one SQLite store, cron and interval schedules, per-window presence, andcodeaf clock, the one process that runs them. Nothing is installed on the OS. Missed slots catch up once, marked late. Closing codeaf pauses a run, and it picks up on reopen.automationtool), type it (/automations add …), or useask herefrom home.eon a row edits an existing one./automationsplace: on the tab bar between Memory and Spend. It shows the list, each automation's history (with the selected run's full result) and run transcripts, plus run now, pause, stop, edit, delete, and open where it was asked./always). The memory rework (memory: one strength — every kept line rides every conversation, never silently #1830) builds on this.internal/standing,/standing, thestandtool, the OS timer, and the v1 resident scheduler.codeaf tickandcodeaf wakeremain as hidden no-ops. Existing standing items are not migrated.Automations.*added,Standing.*removed.ask hereare asked in its pane, and iTerm2 gets banners via OSC 9.--host, a reopened conversation doesn't draw the run lines it missed.How to try it:
make demo-homeand open/automations(alt+7) to see a fortnight of history;enteron a row shows each run's full result.1. When it fires, the line appears there and a banner fires./automations add plants at 6pm say "water the plants"and press1. Then→thenron its row: the line appears on the page.ctrl+c. codeaf leaves at once, and the run picks up on reopen.Design: docs/design/automations/DESIGN.md
How it was checked
make test-touched(baseorigin/dev): every touched package green. The only failure isTestGrepWithoutRipgrepFindsWhatRipgrepWouldFind, which the classifier reports as already failing on the base on this Mac.go test -tags e2e -run TestAutomationsE2E ./internal/e2e/againstbin/codeaf: three subtests pass (ask here at two widths, the clock saying a reminder into its conversation).go test -race ./internal/automation/,go test -race -run TestDoRunKeepsFailedAndTimedOutRecordsOutsideRepository ./cmd/codeaf/, focusedmake test-focusoninternal/sessionandinternal/tui3,make test-laws, and the e2e host-guard timer tests. All green.User journeys
Tried by hand with the owner in iTerm2 over two walkthroughs (the second on the fixed build), plus a few in a throwaway home in tmux. Each: what the person does, then what they see.
1on the card. Two minutes later, a dimstretch · doneline appears in that conversation, and an iTerm2 banner appears even while codeaf is in front. The first banner is followed once by a line pointing at Notification settings./automations add …with a time and asayline, then press1. Then→andron its row: the line appears on the/automationspage and a banner fires. The second walkthrough usedat 6pm, the first a reminder named after watering the plants.eon a finished reminder, move its time later and save. The row went back toreminder · today at …in tmux; the owner saw it stayfinishedonce and it could not be reproduced. Changing one from chat (the change card) lives in automations: the conversation can change one in place #1829 (not run by hand here).couldn't check · couldn't decide: no API key, because the clock lacked the shell's key; that led to the key fixes. On the fixed build the owner's walkthrough, including a watch, came back fine.enteron the row showed the whole report in normal text. Quit while a run was going: codeaf left at once, and the run picked up on reopen. Stopping atyour callwhen it would ask, and the daily spending limit, are covered by tests (not run by hand)./alwaysin a conversation saidmemory is off for this sessionin the owner's setup, because the background engine had read the memory switch once. In a fresh home in tmux it kept the rule (always · … · in this project). The fix is memory: one strength — every kept line rides every conversation, never silently #1830.--host(not run by hand): covered by the loopback wire tests, and a~folder typed over the wire lands in the far machine's home.Checklist
docs/changes/unreleased/1831-automations.md.internal/manual/chat/automations.mdand every page that named standing..github/known-red.txt.🤖 Generated with Claude Code