Install
npx skillscat add chnlich/charlie-bot/plan-approval Install via the SkillsCat registry.
Scope
- This skill governs only the CharlieBot master-to-user approval boundary; a
delegated task is already past that boundary. - Plan approval and runtime delegation authorization are separate boundaries. The
approval interaction approves the settled plan terms; the runtime gate decides
whether a later/delegateor/improverequest has an active user-message
authorization window. - A delegated worker, reviewer, or improve-loop worker does not present another plan
and does not wait for anothertake off; it follows its delegated task contract. - A delegated agent still stops and reports a blocker, contract conflict, or required
scope expansion.
The principle
The user judges before what they cannot judge after. Exactly two things need that
before-judgment: the design, because implementation builds on it and reversing it
later means redoing the work; and any action the user cannot take back afterward —
because something is destroyed, or because it has already reached other people.
Everything else the user can still correct after the fact, so it belongs to
execution — done autonomously, logged, and surfaced in the completion report,
which is where after-the-fact judgment happens.
approval object = sections 1 and 3 + 4.1 Schema + resolved Trade-offs + entries
promoted from Other Details. These are the exact terms a "take off" approves. The BLOCK KIT comment
in prompts/plan_template.html is the canonical grammar for the plan surface; do
not restate it here.
Understanding
An understanding page precedes the plan when the master must first align the reading
(the trigger and its exemptions live in the master prompt).
- The page is
artifacts/understanding_<slug>_v<n>.html, reusing the head and style ofprompts/plan_template.html. Six blocks: goal in one sentence carrying the why one level up; the
deliverable through two or three concrete examples; acceptance criteria, each a trigger
condition plus an observable behavior (EARS phrasing, "WHEN THE SYSTEM
SHALL ", is an example shape, not a requirement); non-goals; numbered
divergences rendered asdiv.forkblocks, each carrying the fork grammar's
folded explainer (block kit section 5,prompts/plan_template.html); Linear. - The Linear block carries the whitelist gate, the two-path recall, the candidate or
draft choice, the take off gate, and the identifier readback. It appears only for
repos marked Linear-tracked on the memory entrycharliebot/workspace-repos, read
withcharliebot memory query --topic charliebotwhile drafting; a repo not tracked
carries no Linear block and no explanation. When the marker list is absent altogether
the block states in one line that the whitelist is not configured, because an absent
list and an all-untracked list are otherwise indistinguishable and the mechanism
would fail silently. Two-path recall per thelinearskill is presented as either a
candidate list (identifier, title, state, project, each with a one-line relevance
judgement) or a conclusion that nothing matches plus a ready-to-file draft; never pick
a match silently, the user decides. The draft's fields are an English title and body
(goal, deliverables, acceptance), team, project, assignee, and priority, resolved from
the Linear defaults held in memory with priority defaulting to medium; a new ticket's
project follows the closest candidate's project and is named in the draft so the user
can change it. The write waits for take off per the master prompt's External System
Writes rule, and the authorization may ride in the same message that answers the
divergences. After the ticket is created, read its identifier back from the API and carry
it as a header meta chip on the understanding page and on the plan that follows. - Don't guess: any point the request leaves unstated where different readings lead to
different designs must appear as a numbered divergence; never silently pick a reading. - No how: an understanding contains no implementation mechanisms or technology choices;
design content belongs to the subsequent plan. - Facts before design: when the fix follows from why something happened, settle the
root cause before drafting and state the case for it in one block between goal and
deliverable, each claim carrying its evidence anchor. - Not registered in the plan registry, no verify worker, and the understanding confirmation does
not use take off. The user confirms by answering the numbered divergences in chat; unmentioned
items take their recommendation. Confirmation is ordinary feedback and introduces no new
approval token. External system writes follow the master prompt's External System Writes rule. - Before sharing, the page passes the cold-read gate (file-server skill) with
--genre understandingand the originating request as the trigger, revised until answer (7) is
none; the share message carries the same one-line result. - The subsequent plan carries the confirmed understanding's file path as a header
meta chip; section 1 states the goal in its own words. - The page as it opens obeys the plan template's page budget (the BLOCK KIT comment in
prompts/plan_template.html); the always-visible minimum here is the goal sentence and
each divergence's question, recommendation, and trade lines.
Plan
- Research the codebase first; present the plan as a decision surface following the
template block kit, with numbered Trade-offs for the choices the user must judge. - Contract text (rule sentences the plan lands verbatim in prompt docs, skills, or task
specs) is drafted to the standing-reality form and checked block by block beforecharliebot plan present: each sentence opens with what stands or works ("one post
carries the whole reply up to the limit", over "in one post unless it exceeds the
limit"), a bare prohibition is recast as the working practice it protects ("each rule
keeps one home; other files reference it", in place of the ban it replaces), the
exception arrives as a bounded case rather than the sentence's spine, and dashes give
way to commas, colons, semicolons, or a restructure (code excepted). - Render the artifact per the USAGE note atop the BLOCK KIT comment in
prompts/plan_template.html. - Run the cold-read gate (file-server skill) with
--genre planbefore everycharliebot plan presentoramend, trigger per the gate's rule, and revise until
answer (7) is none. The hand-over message for a plan or understanding version carries
one line with the cold read's result: the count of terms question 7 still lists (zero
when clean) and the count the revisions cleared. - Register before presenting via
charliebot plan present(verbs percharliebot plan --help). The artifact's status chip is a presentation-time snapshot; the plan registry is the live truth. Record the code baseline when the plan pins one. - An improve-loop takeoff plan follows this same contract; its approval object covers
repo, goal, iterations, work branch, and merge-back — loop parameters with reasonable
alternatives (iteration count, merge-back) make natural Trade-offs. - End with: "Say take off when ready to implement."
Feedback
- Replies that touch the plan are feedback, not approval: Trade-off resolutions by
number, added constraints, questions, changed terms. Fold each into the plan and
re-present what changed, then wait. A revision registers withcharliebot plan amend,
which requires--note: the one line saying why this version differs from its
predecessor. The note rides on the version record; the body stays the complete
current design and carries no revision marks, and the reader gets the differences
fromcharliebot plan diff. - A style finding on one passage stands for its pattern: sweep the whole artifact for that
pattern and fold every fix into the same revision. - Only the user changes the goal. Versions answer feedback within the standing goal; a changed
goal is a new plan —charliebot plan presentopens the new lineage and the old one closes
as superseded. - When the user asks to control an Other Details entry, promote it; it joins the
approval object. Unmentioned Trade-offs take their recommendation at approval.
Approval
- "take off" (case-insensitive) is the only trigger. Anything else — "go ahead",
"LGTM", "ship it" — gets: "Say take off to confirm." - Trade-off resolutions may ride in the approval message ("1 default, 2 both, take
off"): resolve them first; the approval covers the result. - Approval binds to the approval object as it stands: progress never expires it,
change does. If an approval-object term must change mid-flight, surface it to the user;
nothing forces a re-presentation, the user decides whether to revisit. - Verify is a required independent step; its results live in the verify thread's own log, never in the
plan registry.approverecords a takeoff unconditionally; the runtime delegation gate reads the chat
log, not the registry, so approve bookkeeping does not gate execution. - After the user says take off, record it via
charliebot plan approve. - After
charliebot plan approveand before delegation, post one English comment on
the plan's ticket carrying the design conclusion and the choices the user judged. One
comment per plan lineage. The plan stage never creates a ticket; a plan whose work has
no ticket posts nothing. Design changes after take off are reported to the user as
deviations and are not written back to Linear.
Verify
- Fixed order: draft → register with
charliebot plan present→ verify → revise → hand the
plan to the user with its findings. Verify is a read-only repo-less delegation and runs on
a registered plan, so the goal it measures against has one home and the plan is listed
while the rounds run. - Verify checks fidelity — claims against evidence — and adequacy: whether the design,
assumed accurate and implemented, entails what section 1 claims. Adequacy reads
section 1 as the goal statement only; scope boundaries, thresholds, and exemptions
stated in Context, section 3, 4.1, or Trade-offs bind adequacy equally, so section 1 never
restates them. Quote the confirmed understanding's file path in the spec as the
adequacy reference when one exists; otherwise quote the originating request. Without
one of these, adequacy cannot judge section 1 against what was asked. - Every spec declares its scope, and a spec that declares neither is verified as full.
The first round of a lineage declares full; a revision round answering findings
declares delta and re-checks the declared terms, their dependents, and whether prior
findings are closed. The declared terms are the output ofcharliebot plan diff
quoted into the spec, not restated by the author. Adequacy's whole-plan refutation
belongs to full rounds, so a revision that changes the design's structure declares
full again. - Every round of one plan measures with the same ruler: the spec's Goal quotes the registered
version's section 1 by path, and cites fidelity and adequacy as defined here. A round that
wants a wider question puts that question to the user. - Adequacy findings are advisory.
gap-design:says the mechanism looks short of the
goal — weigh it and revise the design if it holds.gap-goal:says the goal itself may
be misread — put that question to the user. - A revision answers findings by correcting the plan against the goal it was registered with;
section 1 keeps saying what the first version said. When a finding argues the goal itself
is the problem, that is agap-goal:question for the user. - Report the adequacy findings when presenting the plan, so the user can weigh them too.
Runtime delegation authorization
This runtime contract is separate from the plan-approval interaction above. It is
derived statelessly from the existing chat event log and applies at the three
request-entry checkpoints — /api/internal/delegate, /api/internal/improve,
and /api/internal/session-message delivering an agent message to a worker node
(the same judgment the worker's creation applies). There is no check at Run
launch: once a Run is registered, review Runs, manual retries, startup recovery
and cron fires are never withheld by later conversation.
verifyis always allowed without authorization and remains repo-less.- A real user event is
ET.USERwith stringcontent. Scheduled-trigger events
areET.SCHEDULED_TRIGGER, notET.USER, and are excluded on that basis.
Agent-relay events (ET.AGENT_MESSAGE, injected cross-session via/api/internal/session-message) are excluded by type alongsidescheduled_trigger: anagent_messageneither mints nor revokes an
authorization window. Nested
tool-result events are not real user messages for authorization. - Match
pre take offandtake offindependently, case-insensitively, after
normalizing consecutive whitespace. Thetake offsubstring insidepre take off
counts, so one message can create both windows. - A real
pre take offauthorizes every non-verifybehavior for exactly 12 hours
from its valid UTC event timestamp, survives later real user messages, and is
restarted by a new pre token. Missing or unparseable pre timestamps fail closed. - Ordinary
take offauthorizes every non-verifydelegation type without a count
limit when the latest real user message contains it. The next real user message
ends that window. Scheduled-trigger and nested tool-result events do not mint or cancel it. - Scheduled fires stay outside this user-facing gate. No authorization file, field,
event, counter, lease, consumption marker, orTASK_DELEGATEDauthorization read is
permitted; it remains delegation history/UI data.
Execution
- Default to acting. This is the reversibility test: if you can undo an operation
alone at similar cost and its effect stays within what you own (reaching neither
other people nor systems they rely on), do it without asking. - When reality forces a change that leaves the approval object intact, make it,
log it as a deviation, and keep going. - Between "take off" and the report there is nothing to ask: return to the user
only at a checkpoint the plan assigns to the user, at an unapproved action that
fails the test, or at a blocking failure. Progress updates are fine; requests
for permission are not.
Report
- At completion or at a blocking failure, account for every approval-object term:
delivered or deviated. Each deviation is a retroactive Trade-off — approved term,
what landed, one-line reason — accepted by default or reverted on request; the revert becomes a new delegation.