Skip to content

automations: replace standing orders with reminders, scheduled work and watches - #1831

Merged
ZeroPoint95 merged 52 commits into
devfrom
zeropoint95/codeaf-cron-system-7b4f2b
Oct 14, 2026
Merged

ZeroPoint95 merged 52 commits into
devfrom
zeropoint95/codeaf-cron-system-7b4f2b

Conversation

@ZeroPoint95

@ZeroPoint95 ZeroPoint95 commented Oct 14, 2026 •

Copy link
Copy Markdown
Collaborator

Replaces standing orders with automations: reminders, scheduled work and watches that run while a codeaf window is open.

What changed

  • New engine: internal/automation, with one SQLite store, cron and interval schedules, per-window presence, and codeaf 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.
  • Three ways in, one card: say it in a conversation (the automation tool), type it (/automations add …), or use ask here from home. e on a row edits an existing one.
  • The /automations place: 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.
  • Results: one dim line in the conversation that made it (the model isn't woken), plus a desktop notification.
  • Rules: they become memories marked always (/always). The memory rework (memory: one strength — every kept line rides every conversation, never silently #1830) builds on this.
  • Removed: internal/standing, /standing, the stand tool, the OS timer, and the v1 resident scheduler. codeaf tick and codeaf wake remain as hidden no-ops. Existing standing items are not migrated.
  • Wire version 21: Automations.* added, Standing.* removed.
  • Fixed prompt prefix: down from 57,749 to 52,713 bytes, and both waivers are lowered to the new measurement.
  • Also: approvals inside ask here are asked in its pane, and iTerm2 gets banners via OSC 9.
  • Known gaps:
    • Over --host, a reopened conversation doesn't draw the run lines it missed.
    • A codeaf-branded macOS banner needs a Developer ID-signed helper.
    • A run's separate worktree is kept until the person lands or discards it.

How to try it:

  1. Run make demo-home and open /automations (alt+7) to see a fortnight of history; enter on a row shows each run's full result.
  2. In a conversation, say "remind me in 2 minutes to stretch" and press 1. When it fires, the line appears there and a banner fires.
  3. Type /automations add plants at 6pm say "water the plants" and press 1. Then → then r on its row: the line appears on the page.
  4. Start a run of work and quit with 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 (base origin/dev): every touched package green. The only failure is TestGrepWithoutRipgrepFindsWhatRipgrepWouldFind, which the classifier reports as already failing on the base on this Mac.
  • go test -tags e2e -run TestAutomationsE2E ./internal/e2e/ against bin/codeaf: three subtests pass (ask here at two widths, the clock saying a reminder into its conversation).
  • After review: go test -race ./internal/automation/, go test -race -run TestDoRunKeepsFailedAndTimedOutRecordsOutsideRepository ./cmd/codeaf/, focused make test-focus on internal/session and internal/tui3, make test-laws, and the e2e host-guard timer tests. All green.
  • A manual walkthrough with the owner in iTerm2 covering banners, the list, editing, watches and quitting.

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.

  1. Say "remind me in 2 minutes to stretch", press 1 on the card. Two minutes later, a dim stretch · done line 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.
  2. Type /automations add … with a time and a say line, then press 1. Then → and r on its row: the line appears on the /automations page and a banner fires. The second walkthrough used at 6pm, the first a reminder named after watering the plants.
  3. Press e on a finished reminder, move its time later and save. The row went back to reminder · today at … in tmux; the owner saw it stay finished once 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).
  4. A watch: in the first walkthrough a check said 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.
  5. Work: "look up the youtuber … and tell me the title of his latest video" ran on its own, sent a banner with the answer, and enter on 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 at your call when it would ask, and the daily spending limit, are covered by tests (not run by hand).
  6. Close codeaf past a reminder's time, then reopen: it fires once, marked late.
  7. /always in a conversation said memory is off for this session in 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.
  8. Over --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

  • A change entry: docs/changes/unreleased/1831-automations.md.
  • The manual knows about it: internal/manual/chat/automations.md and every page that named standing.
  • No new line in .github/known-red.txt.
  • Only my own paths are staged.

🤖 Generated with Claude Code

ZeroPoint95 and others added 30 commits October 10, 2026 00:07
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
…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
…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>
ZeroPoint95 and others added 17 commits October 10, 2026 02:55
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>
…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>
- 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
ZeroPoint95 marked this pull request as ready for review October 14, 2026 21:56
ZeroPoint95 and others added 3 commits October 14, 2026 18:28
…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
ZeroPoint95 merged commit 966e2a7 into dev Oct 14, 2026
9 checks passed
@ZeroPoint95
ZeroPoint95 deleted the zeropoint95/codeaf-cron-system-7b4f2b branch October 14, 2026 23:42
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant