Build AgentGuide — versioned CLAUDE.md maintenance
The app-owned agent guide at every board root (DESIGN/08 ▸ The agent guide): version-gated by a first-line marker (v5, superseding the pathfinder's v4 guides on real boards), rewritten when missing or older, byte-for-byte untouched when current or newer. A markerless CLAUDE.md is displaced to CLAUDE.user.md when that name is free — never clobbered — and the guide write is skipped with a log when it isn't. Symlinks, folders, and read-only volumes are skipped in silence; the write rides performWrite's bracket as an app-mediated Writer operation (new WriteOperation.agentGuide), so the echo lands appMediated and the Pro-era committer can attribute it honestly later. Hooked at store acquire (beside the loose-file relocation, after the watcher exists) and on every successful reload — the guide self-heals from foreign deletion or rollback, pre-wiring 06's acknowledged undo bounce. The refresh memo arms before each attempt and clears on a successful write, so a failing write can't hot-loop and a foreign deletion stays healable. First-line-only marker parsing (no Regex); guide content is one swappable literal, finalized under the next card. Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -2362,6 +2362,21 @@ public enum WriteOperation: Sendable, Equatable, CustomStringConvertible {
|
||||
/// never the Finder-renamed one it would have landed under.
|
||||
case relocateLooseFile(filename: String)
|
||||
|
||||
/// The board-root `CLAUDE.md` being written or upgraded — and the rescue move that precedes it
|
||||
/// when a markerless one has to be displaced to `CLAUDE.user.md` (08-agent-integration.md ▸ The
|
||||
/// agent guide; `AgentGuide`).
|
||||
///
|
||||
/// **No payload**, unlike every other case that names something: there is exactly one guide per
|
||||
/// board, its filename is fixed, and it is not an item with a title. Its own case on
|
||||
/// `.relocateLooseFile`'s reasoning, doubled — this is work the *app* started on its own, for a
|
||||
/// file the user did not create, does not own and may not know exists; folding it into any
|
||||
/// gesture's phrasing would name an act that never happened.
|
||||
///
|
||||
/// One case rather than two (the move and the write) deliberately: they ride one bracket and
|
||||
/// have one outcome the user could care about — the board's guide is not up to date — and a
|
||||
/// second phrasing for "couldn't move a file you have never seen" would explain nothing.
|
||||
case agentGuide
|
||||
|
||||
/// A Preview task-list checkbox being ticked or unticked (05-card-window.md ▸ Preview).
|
||||
///
|
||||
/// Its own case rather than a fold into `.rename`'s or `.style`'s neighbourhood, on the
|
||||
@@ -2399,7 +2414,8 @@ public enum WriteOperation: Sendable, Equatable, CustomStringConvertible {
|
||||
/// on — identity for the cases with no title slot at all: `createBoard`/`createLane`/
|
||||
/// `createCard` are minting a file, not reading one; `importAttachment`, `removeAttachment` and
|
||||
/// `relocateLooseFile` carry a filename, which is the name the user is looking at and the only
|
||||
/// one their banner should say; `listAttachments` and `renumberChildren` name no single item.
|
||||
/// one their banner should say; `listAttachments`, `renumberChildren` and `agentGuide` name no
|
||||
/// single item.
|
||||
/// Called once, right where the operation's `readDocument` succeeds — `updateIndex` itself
|
||||
/// (which covers every case that funnels through it: renumber, delete, restore, style, and
|
||||
/// the tail end of move/copy) and the move/copy pre-flight, before the folder travels or the
|
||||
@@ -2408,7 +2424,7 @@ public enum WriteOperation: Sendable, Equatable, CustomStringConvertible {
|
||||
public func withTitle(_ title: String?) -> WriteOperation {
|
||||
switch self {
|
||||
case .createBoard, .createLane, .createCard, .importAttachment, .listAttachments,
|
||||
.removeAttachment, .renumberChildren, .relocateLooseFile:
|
||||
.removeAttachment, .renumberChildren, .relocateLooseFile, .agentGuide:
|
||||
self
|
||||
case .move: .move(title: title)
|
||||
case .reorder: .reorder(title: title)
|
||||
@@ -2454,6 +2470,7 @@ public enum WriteOperation: Sendable, Equatable, CustomStringConvertible {
|
||||
case let .removeAttachment(filename): "move attachment '\(filename)' to the Trash"
|
||||
case .renumberChildren: "renumber children"
|
||||
case let .relocateLooseFile(filename): "relocate loose file '\(filename)'"
|
||||
case .agentGuide: "update the agent guide"
|
||||
case let .toggleTask(title): Self.phrase("toggle a checkbox in", title)
|
||||
case let .editBody(title): Self.phrase("save the body of", title)
|
||||
case let .rawSource(title): Self.phrase("apply source changes to", title)
|
||||
|
||||
Reference in New Issue
Block a user