@plinth-music/cli 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/dist/build-stamp.json +2 -2
- package/dist/cli.js +47 -7
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
Notable changes to `@plinth-music/cli`. Grouped by what a user notices, not by PR.
|
|
4
4
|
|
|
5
|
+
## 0.18.0 - 2026-09-04
|
|
6
|
+
|
|
7
|
+
Three code PRs since `0.17.0` (`v0.17.0..3ece28b`, #170, #171, #173; #169 and #172 docs).
|
|
8
|
+
A minor because every member session is now told something different, and the generated
|
|
9
|
+
deny list refuses 32 tool names it did not refuse before.
|
|
10
|
+
|
|
11
|
+
⚠️ **Your sessions are no longer told that writing a calendar date is impossible.** Plinth's
|
|
12
|
+
MCP server gained `preview_` / `create_` / `update_calendar_entry` on 3 September, and 0.17.0
|
|
13
|
+
shipped injected grounding and command files that denied any such route existed — a false
|
|
14
|
+
denial an agent acts on by giving up and leaving the date wrong. The grounding block and both
|
|
15
|
+
`/plinth:start` and `/plinth:close` now name the route and the order it runs in: propose with
|
|
16
|
+
`preview_calendar_entry`, put the proposal to a person, and only once they agree pass the
|
|
17
|
+
token it minted to the writer. Agreement comes before the token in every one of those
|
|
18
|
+
sentences, deliberately — nothing outside the desktop cockpit asks a human anything, so on a
|
|
19
|
+
plain install that instruction is the whole gate.
|
|
20
|
+
|
|
21
|
+
⚠️ **Calendar deletion and cancellation are refused again, on every MCP server: the deny list
|
|
22
|
+
goes 91 to 123 patterns.** The rename that opened the sanctioned write path also retired a
|
|
23
|
+
guarantee, because the old patterns were anchored on the noun `event` — so
|
|
24
|
+
`delete_calendar_entry` on anyone's server was refused by nothing. Thirty-two patterns
|
|
25
|
+
anchored on `calendar` and `entry` restore it. Two consequences worth knowing: this refuses a
|
|
26
|
+
Plinth `delete_calendar_entry` too (none exists and none is planned, so if one ever ships it
|
|
27
|
+
arrives denied rather than surprising somebody), and `delete` matches inside `deleted`, so a
|
|
28
|
+
`get_deleted_calendar_entry` would be refused as well.
|
|
29
|
+
|
|
30
|
+
- The injected grounding block grows 215 bytes (12,699 to 12,914). The injection budget is
|
|
31
|
+
fixed, so on a workspace already at it those bytes come out of the memory facts that ride
|
|
32
|
+
into the session head. The facts themselves are untouched on disk and still readable.
|
|
33
|
+
|
|
34
|
+
The desktop app pins `@plinth-music/cli` exact (0.17.0 as of v1.10.0) and picks none of this
|
|
35
|
+
up until its own release repins.
|
|
36
|
+
|
|
5
37
|
## 0.17.0 - 2026-09-03
|
|
6
38
|
|
|
7
39
|
One code PR since `0.16.0` (`v0.16.0..a6209c8`, #165; #167 is tests and comments,
|
package/README.md
CHANGED
|
@@ -29,7 +29,7 @@ plinth start # run the daemon: continuous pull + watch + pu
|
|
|
29
29
|
- `plinth confirm` — review and release destructive batches the daemon has quarantined (apply, or `--discard`).
|
|
30
30
|
- `plinth refresh-context [--workspace <slug>]` — force-regenerate the workspace-root `CLAUDE.md` **and the two generated commands** from the current Plinth schema + workspace. The user-customisable block between the `<!-- BEGIN: user-customisable -->` / `<!-- END -->` markers is always preserved verbatim in every generated file; `CLAUDE.local.md` is never touched.
|
|
31
31
|
- `plinth grounding` — print the session-start grounding block (current date, **who the member is**, entity resolution, write confirmation, workspace rules, workspace memory, user memory). It opens by naming the member: display name, email, role, workspace and machine timezone, and that tasks the agent creates are assigned to them unless told otherwise. That renders from a principal **persisted at login**, not a call at render time — this command runs on every session start, so a round trip would tax all of them and fail offline. An existing login self-heals on the next sync, so no re-login is needed, and a server that does not yet carry `role` renders a shorter true line rather than a dangling clause. Invoked by the generated Claude Code SessionStart hook. **Bounded at 20,000 bytes total.** Only the two memory indexes give: a generated safety primitive is never cut, and if the generated block alone exceeded the budget the indexes collapse to a pointer and the block goes over rather than losing a rule. An index that does not fit whole keeps the **most recently banked** facts, by the date each line carries rather than by position — `workspace-memory.md` supersedes in place, so an updated line keeps its original slot and position does not track age — and renders them in the file's own order, with a note saying how many of how many are shown. **A fact that does not fit whole is named by its title** — its own first sentence, a boundary the member already wrote, with its `[[pointer]]` kept — so the agent knows the fact exists and where to read it. ⚠️ **Naming is preferred over carrying, and that trades depth for breadth:** the naming pass runs first and packs, and whole facts compete for what is left, so on a full index no fact may ride whole at all. A title pays in proportion to how well the hook was written; a fact whose first sentence runs long compresses barely at all, which is why *shorten each fact's first sentence* buys room where *trim the file* does not. `voice.md` is a **pointer, not a payload**: it is read on demand when drafting, never injected, which is what took a live workspace's block from 43,578 bytes to 19,911.
|
|
32
|
-
- `plinth voice-gate` — gate agent-originated copy against the workspace voice rubric. **No longer mounted by the mirror generator** (20 Aug 2026): a generated mirror carries no PreToolUse hook, voice is carried as an instruction by `workspace-rules.md`, and the outbound boundary is a `permissions.deny` list in the generated `.claude/settings.json` that refuses the **send, reply, forward, calendar
|
|
32
|
+
- `plinth voice-gate` — gate agent-originated copy against the workspace voice rubric. **No longer mounted by the mirror generator** (20 Aug 2026): a generated mirror carries no PreToolUse hook, voice is carried as an instruction by `workspace-rules.md`, and the outbound boundary is a `permissions.deny` list in the generated `.claude/settings.json` that refuses the **send, reply, forward, calendar and mail-deletion verbs on any mounted MCP**, not seven tool names — each verb anchored at a word boundary in four positions (start, after `_`, after `-`, and at a camel hump), which is what catches `outlook_send_message` and `send-mail` while leaving `resend_verification` and `list_sent` alone. Spam is the one family that is *not* anchored, and deliberately: no English word contains `spam` as a substring, so the unanchored form has nothing to over-reach into and catches `reportSpam` and `move_to_spam` as well as `mark_message_spam`. Deletion joined on 30 Aug 2026, taking the list from 61 patterns to 91: `trash` bare (nothing reads by *starting* with it, and `empty_trash` falls out for free), `delete` against the `message` / `thread` / `mail` nouns (bare, it would refuse every `mcp__plinth__delete_*` tool), and spam-marking, which Gmail purges after thirty days and is therefore deletion on a fuse. **Plinth's own calendar-write route is deliberately outside the list** (4 Sept 2026). The server renamed those tools to `preview_` / `create_` / `update_calendar_entry` on 3 September, and because the deny dialect has no negation an exception cannot be written as a rule — the carve-out *is* the name. The same rename retired a guarantee, since the calendar families were anchored on the noun `event` and `delete_calendar_entry` on anyone's server was then refused by nothing, so the list went from 91 patterns to **123**: `delete` and `cancel` anchored on `calendar` and `entry`, which refuses calendar deletion on every server again, Plinth's own included. **Drafting, filing, labelling and reading are untouched** — `outlook_send_draft` is denied while `outlook_create_draft` is not, because the discriminator is the verb, never the noun, and archiving a message is a move rather than a deletion. **Two costs are disclosed rather than discovered:** a few reads are caught by name (`getForwardingSettings`, a `list_trash`), and the bare `trash` family also refuses Google Drive's `trash_file` and the only route the live Gmail mount has for discarding a staged draft — that connector exposes no `delete_draft`, so a wrong draft is repaired with `update_draft` instead. Ten holes are recorded as assertions in `tests/context-session-hook.test.ts` rather than as prose — deletion-by-move and Gmail's own label route among them, the latter being the widest, since Gmail expresses TRASH and SPAM as labels and labelling stays allowed. The list is an enumeration and the tests say so out loud. The command still ships and still works, for a hand-wired mount: `--hook` runs it as a PreToolUse hook that blocks non-compliant Gmail drafts; direct mode takes `--file <path>` or stdin and prints the verdict (`--json` for the raw response).
|
|
33
33
|
- `plinth backlinks <target>` — report what points at a target, by reading the local mirror rather than making a network call. `<target>` can be a mirror path (`projects/breadcrumb-trail.md` — including a mirror-root file like `CLAUDE.md`), a bare name (`breadcrumb-trail`), or a wikilink target as written (`Aligned Timeline - 4 June 2026`). Output is file paths with line numbers and the link as written; `--paths-only` emits deduped paths for piping, and stdout carries the answer ALONE — withheld rows never reach the pipe, whatever the display flags say. **Every narrowing is disclosed, and the counts print even when they are zero**, because a filter the caller cannot see is indistinguishable from an empty corpus, and a disclosure that only appears when it bites gives a reader no baseline to judge it against. Two footers carry them: links withheld from the answer (daemon-rendered marker blocks, code spans / HTML comments, and links to a bare name several files answer to), and the corpus line — which workspace was searched, how much of the mirror was read against its full size, and what went unread: `this-fiction · 859 of 880 files scanned (21 non-markdown, 0 unreadable) in 34ms`. `--unfiltered` shows the withheld rows, each tagged with the narrowing that hid it. Non-markdown files are not scanned for links but **do** count as existing, so asking about a PDF in `files/` answers rather than denying it. Exit codes: `0` results found or the target file exists, `1` no such target and nothing links to that name, `2` a bare name several files answer to (it lists them rather than guessing — and every candidate it prints resolves when pasted back), `3` no active workspace, an unknown or malformed workspace slug, or a mirror with nothing to search.
|
|
34
34
|
- `plinth declare <path> --scratchpad <dir> [--label=<text>]` — declare a file in the session scratchpad as a work product, so it appears in the cockpit's work-products panel instead of being lost with the session. Appends one line to an append-only `.plinth-deliverables.jsonl` manifest inside `<dir>`; the manifest records the **path, never the content**, so the panel always points at the live file rather than a snapshot that can go stale. Grounding primitive (j) instructs the agent to run this the moment it writes a deliverable whose only home is the scratchpad. **The scratchpad directory is required and never inferred** (`--scratchpad`, or `PLINTH_SCRATCHPAD_DIR`): this repo learns it from neither the app that spawns the terminal nor the harness that told the agent, so a guessed root would silently widen the containment check every refusal rests on. Refuses, with exit 1, anything outside that directory — including a symlink whose target is outside it — plus a directory, a file that does not exist yet, and a missing root.
|
|
35
35
|
- `plinth review-tier [--repo <path>] [--base <ref>]` — print the code-review tier the current diff earns, `low` or `high`, for use as `/code-review $(plinth review-tier)`. Reads the diff against the merge base — committed, uncommitted **and untracked**, since a brand-new never-added file is invisible to `git diff` and would otherwise be classified as absent — and routes `high` on the risk classes the review rubric names: auth/RLS, optimistic concurrency/CAS, financial math, data-moving migrations, and large **and** multi-subsystem together. **It is a router, not a ceiling**: size alone never escalates, because a blanket cap would kill the concurrency reviews that earn their keep. **The output contract is the safety story.** It is invoked inside `$( )`, where an empty stdout or a non-zero exit would collapse the caller to an unqualified `/code-review` that silently inherits whatever global effort is configured — safe by accident, and indistinguishable from this working. So stdout carries **exactly one token and nothing else**, the exit code is **always 0**, and the reasoning goes **unconditionally to stderr** on both tiers. Anything it cannot classify — not a git repo, no merge base, no default branch, an empty diff — prints `high` and says why on stderr.
|
package/dist/build-stamp.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -7584,7 +7584,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
7584
7584
|
// package.json
|
|
7585
7585
|
var package_default = {
|
|
7586
7586
|
name: "@plinth-music/cli",
|
|
7587
|
-
version: "0.
|
|
7587
|
+
version: "0.18.0",
|
|
7588
7588
|
description: "Plinth capstone sync daemon and CLI",
|
|
7589
7589
|
type: "module",
|
|
7590
7590
|
private: false,
|
|
@@ -27072,7 +27072,7 @@ function composeGroundingBlock(today, workspaceRules, workspaceMemory, userMemor
|
|
|
27072
27072
|
add("grounding", `Plinth session grounding:`, ``, `Today's date: ${today}. You have no inherent sense of the current date and ` + `your training has a knowledge cutoff, so treat this injected date as ` + `authoritative for anything time-relative: deadlines, what counts as ` + `"recent" or "upcoming", and the age of any data or of your own knowledge.`);
|
|
27073
27073
|
if (identity !== null)
|
|
27074
27074
|
add("identity", ``, identity);
|
|
27075
|
-
add("grounding", ``, `Resolve Plinth entities before answering about them. For any answer grounded ` + `in a specific artist, project, task, or other workspace entity, first look ` + `the name up in THIS workspace with the Plinth MCP tools ` + `(\`mcp__plinth__search_entities\`, \`mcp__plinth__list_artists\`, or ` + `\`mcp__plinth__list_projects\`) and ground your answer in what they return. ` + `Do not answer from name recognition alone: a globally famous name may not ` + `exist in this workspace, and an entity here may differ from the public ` + `figure of the same name. If the lookup returns nothing, say so instead of ` + `inventing details.`, ``, `Plan before you write. The first time you call any mutating Plinth MCP tool ` + `in a session (create_*, update_*, delete_*, mark_*: anything that changes ` + `workspace data), do not commit silently: state exactly what you would write, ` + `naming the tool, the entity, and the fields and values, and proceed only after ` + `the user confirms or amends.`, ``, `Write through the canonical surface. In this cockpit the file tree is your edit ` + `surface, so reach for it before the most direct tool. Change prose (document ` + `bodies, free-form notes, anything textual) by editing the mirror markdown ` + `file; the daemon syncs it up. An artist's master context is the clearest case: ` + `it lives in the body of that artist's \`artists/<slug>/_artist.md\` mirror file, ` + `the file the web context pane renders, and one of only two files under ` + `\`artists/<slug>/\` the daemon syncs both ways (\`memory.md\` is the other), ` + `so change it by editing that body, never by creating ` + `a separate document or context entity (e.g. \`create_document\`) the pane won't ` + `render. One carve-out inside that file: a block labelled as rendered from ` + `Plinth is regenerated on every sync and your edits to it are discarded, so ` + `write those through the tool the block names. Change structured fields (task ` + `status, priority, assignees, due dates, a project's category) through the ` + `Plinth MCP (\`mcp__plinth__*\`) or the task file's frontmatter, which is ` + `row-canonical but still written through the validated API. Make a bulk or ` + `destructive change (a mass delete, a gutting overwrite) by editing the file ` + `path, so the daemon's confirm-gate can quarantine it for \`plinth confirm\`. ` + `Never write the database directly, which rules out raw SQL and ` + `\`execute_sql\`, \`apply_migration\` and \`psql\`: those bypass the daemon, the ` + `mirror, the confirm-gate, canonicality, and API validation.`, ``, `Dates belong on the calendar, not in \`key_dates\`. The date surface for an artist ` + `is their mapped Google Calendar; the \`key_dates\` table is retired. Reading ` + `dates is yours, and this mirror already holds them: the daemon projects every ` + `mapped calendar into \`views/calendar/upcoming.md\` and ` + `\`views/calendar/<slug>.md\`, so read those before reaching for a tool ` + `(\`list_artist_calendars\`). They are derived and overwritten, ` + `so they are current only as of the \`generated_at\` in their header - quote that ` + `stamp, never edit them, and check the status line, because a calendar Plinth ` + `could not reach is unknown rather than empty. When a tool is the only way, ` + `resolve the calendar through \`mcp__plinth__list_artist_calendars\` and use its ` + `\`calendar_id\` field, not the mapping row's \`id\`, because the default ` + `\`primary\` is almost never theirs.`, ``, `Writing a date is not yours,
|
|
27075
|
+
add("grounding", ``, `Resolve Plinth entities before answering about them. For any answer grounded ` + `in a specific artist, project, task, or other workspace entity, first look ` + `the name up in THIS workspace with the Plinth MCP tools ` + `(\`mcp__plinth__search_entities\`, \`mcp__plinth__list_artists\`, or ` + `\`mcp__plinth__list_projects\`) and ground your answer in what they return. ` + `Do not answer from name recognition alone: a globally famous name may not ` + `exist in this workspace, and an entity here may differ from the public ` + `figure of the same name. If the lookup returns nothing, say so instead of ` + `inventing details.`, ``, `Plan before you write. The first time you call any mutating Plinth MCP tool ` + `in a session (create_*, update_*, delete_*, mark_*: anything that changes ` + `workspace data), do not commit silently: state exactly what you would write, ` + `naming the tool, the entity, and the fields and values, and proceed only after ` + `the user confirms or amends.`, ``, `Write through the canonical surface. In this cockpit the file tree is your edit ` + `surface, so reach for it before the most direct tool. Change prose (document ` + `bodies, free-form notes, anything textual) by editing the mirror markdown ` + `file; the daemon syncs it up. An artist's master context is the clearest case: ` + `it lives in the body of that artist's \`artists/<slug>/_artist.md\` mirror file, ` + `the file the web context pane renders, and one of only two files under ` + `\`artists/<slug>/\` the daemon syncs both ways (\`memory.md\` is the other), ` + `so change it by editing that body, never by creating ` + `a separate document or context entity (e.g. \`create_document\`) the pane won't ` + `render. One carve-out inside that file: a block labelled as rendered from ` + `Plinth is regenerated on every sync and your edits to it are discarded, so ` + `write those through the tool the block names. Change structured fields (task ` + `status, priority, assignees, due dates, a project's category) through the ` + `Plinth MCP (\`mcp__plinth__*\`) or the task file's frontmatter, which is ` + `row-canonical but still written through the validated API. Make a bulk or ` + `destructive change (a mass delete, a gutting overwrite) by editing the file ` + `path, so the daemon's confirm-gate can quarantine it for \`plinth confirm\`. ` + `Never write the database directly, which rules out raw SQL and ` + `\`execute_sql\`, \`apply_migration\` and \`psql\`: those bypass the daemon, the ` + `mirror, the confirm-gate, canonicality, and API validation.`, ``, `Dates belong on the calendar, not in \`key_dates\`. The date surface for an artist ` + `is their mapped Google Calendar; the \`key_dates\` table is retired. Reading ` + `dates is yours, and this mirror already holds them: the daemon projects every ` + `mapped calendar into \`views/calendar/upcoming.md\` and ` + `\`views/calendar/<slug>.md\`, so read those before reaching for a tool ` + `(\`list_artist_calendars\`). They are derived and overwritten, ` + `so they are current only as of the \`generated_at\` in their header - quote that ` + `stamp, never edit them, and check the status line, because a calendar Plinth ` + `could not reach is unknown rather than empty. When a tool is the only way, ` + `resolve the calendar through \`mcp__plinth__list_artist_calendars\` and use its ` + `\`calendar_id\` field, not the mapping row's \`id\`, because the default ` + `\`primary\` is almost never theirs.`, ``, `Writing a date is not yours to do unasked, and the route is Plinth's own: ` + `propose it with \`preview_calendar_entry\`, put that proposal to the person, ` + `and only once they agree pass the token it minted for exactly that proposal ` + `to \`create_calendar_entry\` or \`update_calendar_entry\`. Nothing else writes ` + `one: ` + `no other calendar tool, and not a shell command line either, the ` + `Google Workspace one included. ` + `Nothing refuses a shell, anywhere, and where Plinth has not configured ` + `this workspace nothing is refused at all: you are the only thing holding ` + `those. Where no calendar is mapped, or a token is refused, that is not a ` + `wall. The way ` + `through is a person, not a workaround, so ` + `say plainly what the change is, say that it goes in through ` + `Plinth's calendar view, and say that a person makes it. Say why, too: a date ` + `left looking handled is worse than one openly outstanding, and a calendar ` + `write goes out to everyone invited the moment it lands and cannot be recalled.`, ``, `Draft email. Never send it. Writing the draft is yours: use the draft tools ` + `(\`create_draft\`, \`update_draft\`), then say where the draft is and what it ` + `says, so the person can read it and send it in their own name. Sending, ` + `replying, forwarding and deleting are not yours, by any route: not a mail tool, and ` + `not a shell command line either. The mail tools are refused for you where ` + `Plinth has configured this workspace. Nothing refuses a shell, anywhere, ` + `and where Plinth has not configured this workspace nothing is refused at ` + `all: you are the only thing holding those. This is not a comment on your ` + `writing. It is that a message which has left the building cannot be recalled, ` + `and one deleted out of a mailbox is not yours to lose; the person whose name ` + `is on it is the one who decides.`);
|
|
27076
27076
|
if (workspaceRules === null && voiceProfile === null) {
|
|
27077
27077
|
add("voice", ``, `Check the voice yourself, because nothing else checks it now. Two files carry ` + `it: \`workspace-rules.md\` at the mirror root holds this workspace's house ` + `style, and \`${VOICE_FILENAME}\` beside it holds your own voice profile, the ` + `sign-off and the habits that belong to one member rather than the team. Read ` + `them before you write and follow them as written, rather than drafting in ` + `your own register and correcting after. Nothing inspects a draft between you ` + `and the person reading it, so the rules in those files are the whole of it.`);
|
|
27078
27078
|
}
|
|
@@ -29346,8 +29346,10 @@ var MANAGED_COMMENT = [
|
|
|
29346
29346
|
"or in .claude/settings.local.json.",
|
|
29347
29347
|
"The permissions.deny entries below are managed the same way. They stop an agent",
|
|
29348
29348
|
"in this workspace sending, replying to or forwarding mail, deleting or trashing",
|
|
29349
|
-
"it, marking it spam, and writing a calendar
|
|
29350
|
-
"
|
|
29349
|
+
"it, marking it spam, and writing a calendar - create, update, delete and cancel",
|
|
29350
|
+
"wherever the name also carries event, plus delete and cancel wherever it carries",
|
|
29351
|
+
"calendar entry; drafting, filing, labelling and reading stay allowed.",
|
|
29352
|
+
"The refusal covers a draft the agent staged itself: on a",
|
|
29351
29353
|
"Gmail mount there is no delete-draft tool, so trashing was the only way to",
|
|
29352
29354
|
"discard one and it is now refused. Fix a wrong draft with update_draft, which",
|
|
29353
29355
|
"keeps its thread. They match by VERB FAMILY rather than by",
|
|
@@ -29355,6 +29357,8 @@ var MANAGED_COMMENT = [
|
|
|
29355
29357
|
"rule set, not four - and the matcher cannot express an alternation, so each",
|
|
29356
29358
|
"spelling needs its own line. That width also catches a few reads whose name",
|
|
29357
29359
|
"merely begins with a send verb - getForwardingSettings is the live example -",
|
|
29360
|
+
"and a few whose name merely CONTAINS one - a calendar read called",
|
|
29361
|
+
"get_deleted_calendar_entry is refused, because delete sits inside deleted -",
|
|
29358
29362
|
"and it stops an agent trashing any file, not only mail: nothing here can tell",
|
|
29359
29363
|
"a mailbox's trash from a drive's.",
|
|
29360
29364
|
"You cannot re-open one of these here: a deny beats an allow, including yours,",
|
|
@@ -29363,6 +29367,10 @@ var MANAGED_COMMENT = [
|
|
|
29363
29367
|
"message that has gone cannot be recalled. Nor is a deleted one yours to lose:",
|
|
29364
29368
|
"it is somebody else's mailbox, spam-marking is deletion on a thirty-day fuse,",
|
|
29365
29369
|
"and neither is undone by noticing afterwards.",
|
|
29370
|
+
"One thing is deliberately NOT on this list, and it is the only exception:",
|
|
29371
|
+
"Plinth's own create_calendar_entry and update_calendar_entry, the sanctioned",
|
|
29372
|
+
"calendar write path, which take a two-step preview-and-confirm of their own",
|
|
29373
|
+
"before anything reaches a calendar.",
|
|
29366
29374
|
"One more entry stops an agent EDITING voice.md, the",
|
|
29367
29375
|
"voice profile it is judged against: that file is yours to write and theirs to read.",
|
|
29368
29376
|
"Your own allow list is untouched, and your own",
|
|
@@ -29441,6 +29449,38 @@ var MANAGED_DENY = [
|
|
|
29441
29449
|
"mcp__*__*_cancel*Event*",
|
|
29442
29450
|
"mcp__*__*-cancel*Event*",
|
|
29443
29451
|
"mcp__*__*Cancel*Event*",
|
|
29452
|
+
"mcp__*__delete*calendar*entry*",
|
|
29453
|
+
"mcp__*__*_delete*calendar*entry*",
|
|
29454
|
+
"mcp__*__*-delete*calendar*entry*",
|
|
29455
|
+
"mcp__*__*Delete*calendar*entry*",
|
|
29456
|
+
"mcp__*__delete*calendar*Entry*",
|
|
29457
|
+
"mcp__*__*_delete*calendar*Entry*",
|
|
29458
|
+
"mcp__*__*-delete*calendar*Entry*",
|
|
29459
|
+
"mcp__*__*Delete*calendar*Entry*",
|
|
29460
|
+
"mcp__*__delete*Calendar*entry*",
|
|
29461
|
+
"mcp__*__*_delete*Calendar*entry*",
|
|
29462
|
+
"mcp__*__*-delete*Calendar*entry*",
|
|
29463
|
+
"mcp__*__*Delete*Calendar*entry*",
|
|
29464
|
+
"mcp__*__delete*Calendar*Entry*",
|
|
29465
|
+
"mcp__*__*_delete*Calendar*Entry*",
|
|
29466
|
+
"mcp__*__*-delete*Calendar*Entry*",
|
|
29467
|
+
"mcp__*__*Delete*Calendar*Entry*",
|
|
29468
|
+
"mcp__*__cancel*calendar*entry*",
|
|
29469
|
+
"mcp__*__*_cancel*calendar*entry*",
|
|
29470
|
+
"mcp__*__*-cancel*calendar*entry*",
|
|
29471
|
+
"mcp__*__*Cancel*calendar*entry*",
|
|
29472
|
+
"mcp__*__cancel*calendar*Entry*",
|
|
29473
|
+
"mcp__*__*_cancel*calendar*Entry*",
|
|
29474
|
+
"mcp__*__*-cancel*calendar*Entry*",
|
|
29475
|
+
"mcp__*__*Cancel*calendar*Entry*",
|
|
29476
|
+
"mcp__*__cancel*Calendar*entry*",
|
|
29477
|
+
"mcp__*__*_cancel*Calendar*entry*",
|
|
29478
|
+
"mcp__*__*-cancel*Calendar*entry*",
|
|
29479
|
+
"mcp__*__*Cancel*Calendar*entry*",
|
|
29480
|
+
"mcp__*__cancel*Calendar*Entry*",
|
|
29481
|
+
"mcp__*__*_cancel*Calendar*Entry*",
|
|
29482
|
+
"mcp__*__*-cancel*Calendar*Entry*",
|
|
29483
|
+
"mcp__*__*Cancel*Calendar*Entry*",
|
|
29444
29484
|
"mcp__*__trash*",
|
|
29445
29485
|
"mcp__*__*_trash*",
|
|
29446
29486
|
"mcp__*__*-trash*",
|
|
@@ -29945,7 +29985,7 @@ function buildStartCommandMd(rosterIsEmpty2, offerTrim = false, stores = BLOB_ME
|
|
|
29945
29985
|
"",
|
|
29946
29986
|
"Then the calendar. It is Plinth's projection of every artist's calendar.",
|
|
29947
29987
|
"",
|
|
29948
|
-
"**This is a FILE READ, not a calendar call, and
|
|
29988
|
+
"**This is a FILE READ, not a calendar call, and Step 2's budget stands unchanged: no calendar call in this brief.** The file is here so that you do not have to make one. **That is a cost rule about the opener, not a closed door** - Plinth has a calendar-write route of its own, named below. Opening a session is not when you take it.",
|
|
29949
29989
|
"",
|
|
29950
29990
|
'**Brief it as of its own `generated_at` stamp, and say the stamp.** A projection is a cache. It is exactly as current as the header says it is and no more, so "nothing on this week" is only ever true as of that moment.',
|
|
29951
29991
|
"",
|
|
@@ -29953,7 +29993,7 @@ function buildStartCommandMd(rosterIsEmpty2, offerTrim = false, stores = BLOB_ME
|
|
|
29953
29993
|
"",
|
|
29954
29994
|
"If the file carries `fetch_state: stale`, the last refresh failed: say how old the dates are rather than reporting them as current. If the file is absent altogether, say the projection has not run yet and carry on without it.",
|
|
29955
29995
|
"",
|
|
29956
|
-
"**Dates are read here and
|
|
29996
|
+
"**Dates are read here, and changing one is not part of this brief.** If something needs moving, say plainly what the change is. After this session's brief it goes one of two ways: propose it with `preview_calendar_entry`, put that proposal to the person, and only once they agree pass the token it minted to `create_calendar_entry` or `update_calendar_entry` - or hand the change to a person to make in Plinth's calendar view.",
|
|
29957
29997
|
"",
|
|
29958
29998
|
"## Step 4: brief, in three lines",
|
|
29959
29999
|
"",
|
|
@@ -30062,7 +30102,7 @@ function buildCloseCommandMd(workspaceSlug, stores = BLOB_MEMORY_STORES) {
|
|
|
30062
30102
|
"- **A note, brief or bio that is a piece of writing in its own right** is a document under `documents/`. That means standalone material somebody would open and read on its own, not a fact you are recording because you learned it - a fact is a memory line, and Step 4b routes it.",
|
|
30063
30103
|
"- **A stable attribute of an artist** - their website, a handle, their bio - is that artist's own field, or the body of `artists/<slug>/_artist.md`.",
|
|
30064
30104
|
"- **A contract, statement or attachment** is a file under `files/`.",
|
|
30065
|
-
"- **A date is live state and belongs in no memory file.** A deadline rides its task as a due date. Every other date is a calendar matter: say plainly what the date is,
|
|
30105
|
+
"- **A date is live state and belongs in no memory file.** A deadline rides its task as a due date. Every other date is a calendar matter: say plainly what the date is, and either propose it with `preview_calendar_entry`, put that proposal to the member, and only once they agree pass the token it minted to `create_calendar_entry` or `update_calendar_entry` - or hand it to a person to add in Plinth's calendar view. Name it in the closing summary either way, so it is not quietly dropped.",
|
|
30066
30106
|
"",
|
|
30067
30107
|
'**A typed fact with no home today is named in the closing summary as "no home yet", and written nowhere.** The case that actually occurs is a contact who belongs to several artists or to none - a publisher who routes writers across the whole roster. Do not pick one artist arbitrarily and do not flatten it into a memory line. **You cannot write it with no artist either: `create_artist_contact` requires `artist_id` or `artist_name` and errors with `Either artist_id or artist_name is required`.** So this is a real gap with no surface behind it today, not a shortcut you are declining to take. Name it in the summary and leave it unwritten; a named gap is useful, and a contact filed under an artist it does not belong to is worse than nothing.',
|
|
30068
30108
|
"",
|