Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/chalk/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "chalk",
"version": "0.13.0",
"version": "0.14.0",
"description": "Capture intent across issues, commits, and PRs — why, not just what"
}
5 changes: 5 additions & 0 deletions plugins/chalk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,13 @@ Chalk also auto-activates when you mention a GitHub issue number (e.g. "#123").
- **Skill** (`issue`): Problem-focused issue descriptions, and keeping them accurate
- **Skill** (`commit`): Contextual commits that capture the why, with chalk integration
- **Skill** (`pr`): Pull requests with intent-driven descriptions
- **Skill** (`voice`): The shared writing voice — Diataxis quadrants, universal principles, the issue/PR section palette
- **Skill** (`mindmap`): The shape of anything the reader has to follow — nested bullets whose parents are claims and whose children back them up
- **Skill** (`goal-tree`): Goal trees, where children accomplish their parent rather than argue for it, and each node is tested for sufficiency
- **Agent** (`github`): Handles all GitHub API interaction, keeping the main context clean

The writing skills are loaded by the others rather than run directly, though you can read any of them yourself with `/chalk:voice`, `/chalk:mindmap` or `/chalk:goal-tree`.

## Permissions

Chalk needs permission to run `gh` commands.
Expand Down
14 changes: 10 additions & 4 deletions plugins/chalk/skills/chalk/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ Interpret MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, etc. per RFC 2119.
Every chalk comment, progress section, issue description, and PR description you touch in this session MUST be drafted in the chalk voice — not your own default prose habits, which read wrong and lose the reasoning the reader needs.

`chalk` carries the issue-tracking mechanics, not the writing voice.
Before drafting any such prose, **load the `chalk:voice` skill** (via the Skill tool) — it holds the Diataxis framing, the universal principles, and the issue/PR section palette.
Then structure the body into sections drawn from that palette, choosing the ones the artefact needs.
Before drafting any such prose, load these (via the Skill tool):

- **`chalk:voice`** — the Diataxis framing, the universal principles, and the issue/PR section palette. Structure the body into sections drawn from that palette, choosing the ones the artefact needs.
- **`chalk:mindmap`** — the shape of the content inside each section, and of each `<details>` block, which behaves like a bullet.
- **`chalk:goal-tree`** — when the artefact carries the direction of the work rather than its history.

**Your audience is the next session on this issue** — a teammate, or you, or an agent starting cold with only the issue in front of it.
That's the most literal case of the rule in "Name your audience" (`chalk:voice`): a comment written for whoever already sat through this session is a comment that helps nobody, because by definition they've gone.

Two artefacts have their own skill carrying rules beyond the voice — load it instead of drafting from here:

Expand Down Expand Up @@ -218,7 +224,7 @@ No date in the header — GitHub timestamps the comment itself.
- Add new items as work emerges.
- Keep details blocks focused — one per theme or work item.

**Writing style**: each `<details>` block is an **explanation** chunk — what was explored, decided, tried. The checklist above is navigation, not a separate quadrant. Follow the explanation-quadrant voice in the `chalk:voice` skill.
**Writing style**: each `<details>` block is an **explanation** chunk — what was explored, decided, tried. The checklist above is navigation, not a separate quadrant. Follow the explanation-quadrant voice in the `chalk:voice` skill, and shape the contents as a mindmap per `chalk:mindmap` — the summary line is the block's subject line and carries the same contract, so a reader who only reads the summaries still follows the session.
Details blocks should read like knowledge-sharing, not a changelog.

## Lifecycle of a Comment
Expand Down Expand Up @@ -260,4 +266,4 @@ See `examples/implementation-comment.md` for a realistic filled-in example.
- All GitHub interaction MUST go through the chalk agent. The main context MUST NOT call `gh` directly for chalk updates.
- The issue description MUST be kept accurate — update facts when they change, but preserve the user's framing and intent.
- `<details>` blocks MUST contain enough context that a future session can pick up where you left off.
- All writing MUST follow the voice in the `chalk:voice` skill — issues, PRs, and chalk comments are explanation artefacts.
- All writing MUST follow the voice in the `chalk:voice` skill — issues, PRs, and chalk comments are explanation artefacts — and MUST be shaped per `chalk:mindmap`.
16 changes: 12 additions & 4 deletions plugins/chalk/skills/commit/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ The user will provide the commit headline as an argument to this command (e.g.,
## Before you draft

The commit body is an **explanation** artefact and MUST be drafted in the chalk voice, not your own default prose habits.
`chalk:commit` loads on its own and does **not** pull the shared voice into context, so before writing the body, **load the `chalk:voice` skill** (via the Skill tool) for the Diataxis framing and the concrete-over-abstract examples.
Unlike a PR, a commit body is a single explanation, not a sectioned document — there's no palette to apply, just the voice.
`chalk:commit` loads on its own and pulls in neither, so before writing the body, load both (via the Skill tool):

- **`chalk:voice`** — the Diataxis framing, the universal principles, and the concrete-over-abstract examples.
- **`chalk:mindmap`** — the shape of the body. A commit body is not prose.

**A commit body is a lead-in line, then a mindmap** — the rules are under "Commit bodies" in `chalk:mindmap`.
What's specific to this skill is *why* it has no palette to apply: unlike a PR, a commit covers one atomic change, so it's a single explanation rather than a sectioned document.
Needing sections is a signal the commit is too big, or that you're writing the PR description in the wrong place.

**Line format: paragraph-per-line** by default.
A commit body is read rendered (`git log`, GitHub, a PR commit list), never as a `git diff`, so put each paragraph on a single line and separate paragraphs with a blank line — sentence-per-line would fragment into `<br>` staccato when rendered.
Expand All @@ -39,9 +45,10 @@ Some projects override this and ask for sentence-per-line in commit messages; fo

A commit body is an **explanation** artefact (see the `chalk:voice` skill).
The diff is the code change; the body explains *why* it exists — decisions, alternatives rejected, constraints, dead ends, counter-intuitive findings, scope boundaries.
Open with the problem or context, then the reasoning.
Embed concrete examples (code snippets, call sites, specific scenarios) as illustrative material.

Open with the lead-in line, then shape the reasoning per "Commit bodies" in `chalk:mindmap`.

4. **Ask clarifying questions** if you can't reconstruct the *why* from the conversation history — particularly around whether something was a deliberate choice vs. a constraint, or intentionally out-of-scope vs. overlooked.

5. **Make the commit** directly with the commit body you've drafted:
Expand Down Expand Up @@ -71,7 +78,8 @@ When chalk is active (tracking a GitHub issue), the commit is part of a larger s

## Constraints

- The commit body MUST follow the explanation-quadrant voice in the `chalk:voice` skill.
- The commit body MUST follow the explanation-quadrant voice in the `chalk:voice` skill, and MUST be shaped as a mindmap per `chalk:mindmap` — a lead-in line, then the tree.
- The commit body MUST NOT contain headings. A tl;dr is optional — the subject line normally serves as one.
- Each commit MUST be an atomic, cohesive unit of change.
- Unrelated changes MUST NOT be staged together.
- The commit body MUST NOT describe what changed — the diff shows that.
Expand Down
90 changes: 90 additions & 0 deletions plugins/chalk/skills/goal-tree/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
name: goal-tree
description: Structure a goal as a tree whose children accomplish their parent rather than argue for it, and test each node for sufficiency. Load whenever writing something with a goal structure in it — the direction or target end state of a piece of work, an issue's Implementation or Future state section, the shape of a problem, or a plan. Covers the sufficiency test, the three kinds of leaf, and the named moves for closing a gap. The chalk, chalk:issue and chalk:pr skills load it alongside chalk:mindmap.
user-invocable: true
---

# Chalk Goal Trees

Interpret MUST, MUST NOT, SHOULD, SHOULD NOT, MAY, etc. per RFC 2119.

A goal tree is a mindmap whose relation is **serves**, not **supports**.
Load `chalk:mindmap` first — subject lines, bolding, shallow nesting, tags and typed IDs all apply here unchanged.
What this skill adds is the completeness test that only a goal tree can support.

## The shape

**The root is the goal.**
Each node's children are what it takes to achieve it, recursively, down to leaves that are directly actionable.

The distinction from an argument tree is the whole reason this is a separate skill: **children don't argue for a parent goal, they accomplish it.**
An argument tree's children are evidence, and you can only ever check whether they're *sound*.
A goal tree's children are work, and a goal states what its children have to add up to — so completeness becomes a real question with a real answer.

## The test at each node is sufficiency

**Assume every child is done, then ask whether the parent is thereby achieved.**

Not "do these look related to the parent?" but "do these, **plus what we already know about this system**, get us there?"

- **The domain knowledge is part of the test.** Half the children in a real tree are only sufficient because of something existing behaviour already guarantees — say that out loud rather than leaning on it silently, because it's exactly the assumption that stops holding.
- **Read bottom-up it's induction.** If each child achieves its part and the children are sufficient, the parent holds, and the root goal is sound.
- **Reason about it explicitly at each node** rather than assuming. `check:` any node where you're unsure the children cover it.
- **This is why goal trees don't need the decomposition note** an argument tree needs (see `chalk:mindmap`). There the split rule is the only thing standing in for completeness; here the parent *is* the yardstick.

**To find a missing child, ask what would stop the parent** rather than what would achieve it.
Enumerating the obstacles to a goal surfaces children that "how do we achieve this?" doesn't.

## Every leaf is one of three things — say which

- **Something we do.** The ordinary case.
- **Something expected of someone or something else** — the user, CI, another team, an upstream library, existing behaviour.
- **A plain fact about the world** we're relying on.

**The middle one is where plans quietly fail**, because an expectation written like a task is a dependency nobody owns.
It reads as covered, it sits in the tree looking like work, and nothing happens until someone notices it was never assigned.

`assumption:` covers whether a leaf has been *verified*; this is the separate question of who's *on the hook*.
A leaf can be both — a verified fact about an upstream library is still someone else's to keep true.

## A gap anywhere invalidates everything above it

Surface it rather than patching around it.
A tree that looks complete because a hole got papered over is worse than one that admits the hole: the next reader trusts it.

**Closing a gap has named moves — pick one deliberately** rather than reflexively adding a task:

- **Achieve the parent a different way.**
- **Reassign it** to someone or something that won't fail like that.
- **Add a step that prevents it.**
- **Make it less likely** without eliminating it.
- **Let it happen and recover afterwards.**
- **Let it happen and limit the damage.**
- **Weaken the goal** so the gap no longer matters.
- **Accept the risk** and move on.

**"Weaken the goal" and "accept the risk" are real answers**, and both MUST be recorded rather than dropped — in **Out of scope** or **Decision rationale**, per the palette in `chalk:voice`.
Scope that was deliberately cut is a decision someone will want the reasoning for later.
Scope that silently evaporated reads as an oversight, and a reader can't tell the two apart.

## In an issue description

**An issue's goal tree sits higher than a plan's.**
The issue answers what has to be true for this to be done; a plan answers which files to touch in what order.
Granular execution — which sub-task is next, what was tried — stays in the chalk comment, per the line the palette already draws.

- **A child may be a link to another issue that owns that part.** This is how the tree stays high-level: `- [ ] Secondaries serve stale reads without blocking the primary — #412`.
- **If a child is doing real work, it probably wants to be a sub-issue.** Then the tree is a readable map *of* the sub-issue graph rather than a second copy of it that drifts. Wire the relationship, don't just write the link — see `chalk:issue`.
- **Palette placement**: **Implementation** for the direction, **Future state** for the target end state — and anywhere else a section has a goal structure to express.
- **A goal tree of the proposed solution is earned, not default.** The rule in `chalk:issue` applies unchanged: include it when the session genuinely worked the direction, and leave it out when the session was about noticing the problem. A speculative solution tree is the most authoritative-looking guess you can put on a card.
- **The `## Progress` checklist is not a goal tree.** It's chalk's flat record of work items and their status. Don't merge them, and don't restructure one into the other.

## Constraints

- Every node's children MUST be work that accomplishes it, not evidence that argues for it. If they argue, it's an argument tree — see `chalk:mindmap`.
- Each node MUST be tested for sufficiency, and any node whose children are not clearly sufficient MUST be marked `check:` rather than left to read as settled.
- A leaf MUST declare which of the three kinds it is where that isn't obvious. An expectation of someone else MUST NOT be written as though it were our own task.
- A gap MUST be surfaced rather than papered over. Closing it MUST be a deliberate choice from the named moves.
- Weakening the goal or accepting a risk MUST be recorded in Out of scope or Decision rationale — these are the two moves that leave no trace in the tree itself.
- A goal tree proposing a solution MUST NOT be written into an issue description the session didn't earn, per `chalk:issue`.
- A goal tree MUST NOT be written into or merged with the `## Progress` section.
24 changes: 19 additions & 5 deletions plugins/chalk/skills/issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,20 @@ It does not track a session against the issue.

An issue description is an **explanation** artefact, and it MUST be drafted against the chalk voice — not your own default prose habits, which read wrong and lose the reasoning the reader needs.

`chalk:issue` loads on its own and does **not** pull the shared voice into context.
Before drafting the body, **load the `chalk:voice` skill** (via the Skill tool) — it carries the Diataxis framing, the universal principles, and the issue/PR section palette.
Then **structure the body into sections drawn from that palette**, choosing the ones this issue needs.
`chalk:issue` loads on its own and pulls in none of the shared skills.
Before drafting the body, load these (via the Skill tool):

- **`chalk:voice`** — the Diataxis framing, the universal principles, and the issue/PR section palette.
- **`chalk:mindmap`** — the shape of the content inside each section.
- **`chalk:goal-tree`** — wherever a section has a goal structure to express, and its children accomplish their parent rather than argue for it.

Then **structure the body into sections drawn from that palette**, choosing the ones this issue needs, and **write each section as a mindmap** — a short tl;dr opening it, then the tree.
A wall of undifferentiated prose is the wrong shape; if you've written one, you skipped this step.

**Your audience is whoever triages this card and whoever picks it up** — most often not you, and often months from now.
They are deciding whether it applies to them and whether it's workable today, from the description alone.
Write for someone who wasn't in the session that found the problem; see "Name your audience" in `chalk:voice`.

**Line format: paragraph-per-line.**
An issue body is read rendered on GitHub, never as a `git diff`.
GitHub renders single newlines as `<br>`, so sentence-per-line fragments into staccato — put each paragraph on a single line, separate paragraphs with a blank line, and let the rendering wrap.
Expand Down Expand Up @@ -70,6 +79,10 @@ GitHub renders single newlines as `<br>`, so sentence-per-line fragments into st
- **Leave them out** when the session was about *noticing* the problem. A guess at the fix, written up as though it were a decision, is worse than no section at all — the next reader can't tell your speculation from a conclusion.
- **When a fix is obvious but unconsidered**, one line under the problem ("probably wants X") is enough. Don't inflate it into an Implementation section.

**Where you do include them, they take a goal tree** (`chalk:goal-tree`) rather than a flat list of tasks.
An issue's goal tree sits higher than a plan's — it answers what has to be true for this to be done, not which files to touch — and a child may be a link to the issue that owns that part, which is what keeps it high-level.
Wire that link as a sub-issue relationship too (step 6), so the tree maps the issue graph rather than duplicating it.

**The description is the source of truth.**
A developer MUST be able to understand the current state of the issue by reading the description alone, without trawling the comments.

Expand Down Expand Up @@ -111,7 +124,8 @@ The description is the source of truth, so it MUST be kept accurate as facts cha

## Constraints

- The issue body MUST follow the explanation-quadrant voice in the `chalk:voice` skill.
- The issue body MUST follow the explanation-quadrant voice in the `chalk:voice` skill, and each section MUST be shaped per `chalk:mindmap`.
- A section whose items accomplish their parent rather than argue for it MUST be shaped as a goal tree per `chalk:goal-tree` — Implementation and Future state, where earned, always are.
- The body MUST be drafted in the main context and handed to the github agent ready to post verbatim. Passing bullet points and asking the agent to "write this up" is not acceptable — it pushes an explanation-quadrant job onto a model that can't do it well.
- All GitHub interaction MUST go through the github agent. The main context MUST NOT call `gh issue` directly.
- The description MUST be understandable on its own, without reading the comments.
Expand All @@ -126,7 +140,7 @@ The description is the source of truth, so it MUST be kept accurate as facts cha
2. Establish the *why* and *why now*; ask if either is unclear
3. Search for an existing issue covering this
4. Gather the concrete evidence
5. Load `chalk:voice`, then draft the title and body against the problem-focused sections of the palette
5. Load `chalk:voice` and `chalk:mindmap` (and `chalk:goal-tree` if any section has a goal structure), then draft the title and body against the problem-focused sections of the palette
6. Ask any clarifying questions if needed
7. Delegate to the github agent to create the issue, and wire up any parent / blocked-by relationships
8. Report the issue number back to the user
Loading