claude-code-kanban 7.5.0 → 7.6.1
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/hub-app.json +5 -0
- package/lib/panes.js +16 -2
- package/lib/parsers.js +27 -2
- package/lib/retention.js +29 -6
- package/lib/session-events.js +154 -42
- package/lib/show.js +385 -0
- package/lib/terminal-client.js +14 -1
- package/lib/terminal-host.js +2 -1
- package/lib/terminal.js +27 -7
- package/package.json +1 -1
- package/plugin/plugins/claude-code-kanban/.claude-plugin/plugin.json +1 -1
- package/plugin/plugins/claude-code-kanban/hooks/doorbell.ts +66 -10
- package/plugin/plugins/claude-code-kanban/hooks/index.ts +2 -0
- package/plugin/plugins/claude-code-kanban/hooks/show.ts +120 -0
- package/plugin/plugins/claude-code-kanban/skills/dispatch/SKILL.md +2 -0
- package/plugin/plugins/claude-code-kanban/skills/kanban/SKILL.md +2 -0
- package/plugin/plugins/claude-code-kanban/skills/show/SKILL.md +45 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/NOTICE.md +27 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/chart.md +58 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/architecture.md +18 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/er.md +10 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/flow.md +13 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/layers.md +10 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/sequence.md +19 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/state.md +12 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/swimlane.md +10 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/timeline.md +9 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram/tree.md +10 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/diagram.md +87 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/explain.md +98 -0
- package/plugin/plugins/claude-code-kanban/skills/show/references/mockup.md +30 -0
- package/plugin/plugins/claude-code-kanban/tests/doorbell.test.ts +69 -10
- package/plugin/plugins/claude-code-kanban/tests/show.test.ts +137 -0
- package/public/app.js +1149 -108
- package/public/index.html +7 -6
- package/public/style.css +770 -9
- package/public/terminal-frame.js +0 -2
- package/public/tree-highlight.js +137 -15
- package/server.js +71 -24
- package/lib/dispatch.js +0 -32
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { EngineInterface, Register } from 'claude-code'
|
|
2
|
+
import { cckRoot } from './context'
|
|
3
|
+
|
|
4
|
+
export const TOOL = 'mcp__claude-code-kanban__show'
|
|
5
|
+
export const SKILL_LINE = /^\s*-\s*claude-code-kanban:show(?=:|\s*$)/
|
|
6
|
+
|
|
7
|
+
type ShowInput = { title: string; key?: string; kind?: 'markdown' | 'html'; file?: string }
|
|
8
|
+
type Shown = { title: string; key?: string | null; index: number; count: number; path?: string | null }
|
|
9
|
+
|
|
10
|
+
export function boardPort(cckUrl: string) {
|
|
11
|
+
return /^[a-z]+:\/\/[^/]*:(\d+)(?:\/|$)/i.exec(cckUrl)?.[1]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function shownText({ title, key, index, count, path }: Shown, claim = false) {
|
|
15
|
+
const at = `"${title}" (${key ? `${key}, ` : ''}${index}/${count})`
|
|
16
|
+
return claim ? `Card ${at} is ready. Write it to ${path}; the card refreshes on each save.` : `Shown ${at}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function dropSkillLine(listing: string) {
|
|
20
|
+
return listing
|
|
21
|
+
.split('\n')
|
|
22
|
+
.filter(l => !SKILL_LINE.test(l))
|
|
23
|
+
.join('\n')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let cck: Promise<string> | undefined
|
|
27
|
+
|
|
28
|
+
function cckDir($: EngineInterface) {
|
|
29
|
+
cck ??= Promise.all([$.env.get('CLAUDE_CONFIG_DIR'), $.env.get('HOME'), $.env.get('USERPROFILE')]).then(
|
|
30
|
+
([configDir, home, userProfile]) => cckRoot(configDir, home, userProfile),
|
|
31
|
+
)
|
|
32
|
+
return cck
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let target: Promise<{ url: string; terminalId: string } | undefined> | undefined
|
|
36
|
+
|
|
37
|
+
// Both vars come from ptyEnv, so only a session started in cck's embedded terminal has them.
|
|
38
|
+
function terminal($: EngineInterface) {
|
|
39
|
+
target ??= Promise.all([$.env.get('CCK_URL'), $.env.get('CCK_TERMINAL_ID')]).then(([url, terminalId]) =>
|
|
40
|
+
url && terminalId ? { url: url.replace(/\/+$/, ''), terminalId } : undefined,
|
|
41
|
+
)
|
|
42
|
+
return target
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Read on every post, the way cli.js reads it for dispatch: a restarted board writes a new token.
|
|
46
|
+
async function terminalToken($: EngineInterface, url: string) {
|
|
47
|
+
const port = boardPort(url)
|
|
48
|
+
if (!port) return undefined
|
|
49
|
+
try {
|
|
50
|
+
const { token } = JSON.parse(await $.fs.read(`${await cckDir($)}/terminal-tokens/${port}.json`))
|
|
51
|
+
return typeof token === 'string' && token ? token : undefined
|
|
52
|
+
} catch {
|
|
53
|
+
return undefined
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function errorText(status: number, text: string) {
|
|
58
|
+
try {
|
|
59
|
+
const { error } = JSON.parse(text)
|
|
60
|
+
if (typeof error === 'string' && error) return error
|
|
61
|
+
} catch {}
|
|
62
|
+
return `cck answered HTTP ${status}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function post($: EngineInterface, input: ShowInput) {
|
|
66
|
+
const t = await terminal($)
|
|
67
|
+
if (!t) return { deny: 'The overlay needs a Claude Code session started in the cck terminal.' }
|
|
68
|
+
const token = await terminalToken($, t.url)
|
|
69
|
+
if (!token) return { deny: `No terminal token for the cck server at ${t.url}. It must run with the terminal enabled.` }
|
|
70
|
+
const { title, key, kind, file } = input
|
|
71
|
+
const body = JSON.stringify({ sessionId: await $.session.id(), title, key, kind, file })
|
|
72
|
+
let res: Awaited<ReturnType<EngineInterface['http']['fetch']>>
|
|
73
|
+
try {
|
|
74
|
+
res = await $.http.fetch(`${t.url}/api/terminals/${encodeURIComponent(t.terminalId)}/show`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: { 'content-type': 'application/json', 'x-terminal-token': token },
|
|
77
|
+
body,
|
|
78
|
+
})
|
|
79
|
+
} catch (err) {
|
|
80
|
+
return { deny: `Cannot reach cck at ${t.url}: ${err instanceof Error ? err.message : String(err)}` }
|
|
81
|
+
}
|
|
82
|
+
if (!res.ok) return { deny: errorText(res.status, res.text) }
|
|
83
|
+
return { result: shownText(JSON.parse(res.text) as Shown, file == null) }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// A -p run is detached from the terminal, so only an interactive session gets the tool.
|
|
87
|
+
export const register: Register = on => {
|
|
88
|
+
on('session.start', { isInteractive: true }, async ($, e, next) => {
|
|
89
|
+
if (await terminal($)) {
|
|
90
|
+
await $.tool.register({
|
|
91
|
+
name: 'show',
|
|
92
|
+
description:
|
|
93
|
+
'Show a card in the cck overlay above this terminal. Post one when the user asks you to show, draw or visualize something, or when your answer is a comparison of 4 or more rows, a flow, or numbers over time. Pick the form that makes the point best: a table, chart, diagram, mockup, small widget or a mix. Give each card a key that names what it shows (for example latency-chart), and post again with that key to update the card in place instead of adding a new one. Without file, the tool answers with a path: write the card there with Write, and change it with Edit; the card refreshes on each save. Pass file to show a file that already exists. To explain code with a call stack or a tree, load the claude-code-kanban:show skill first for the notation. The user sees the rendered card and knows you do not; in your reply, say what the card shows, and take the render as given.',
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: 'object',
|
|
96
|
+
properties: {
|
|
97
|
+
title: { type: 'string', description: 'Card title' },
|
|
98
|
+
kind: {
|
|
99
|
+
type: 'string',
|
|
100
|
+
enum: ['markdown', 'html'],
|
|
101
|
+
description:
|
|
102
|
+
'markdown (default): mermaid, diff and code fences render. html: a body fragment; load the claude-code-kanban:show skill first for the HTML contract',
|
|
103
|
+
},
|
|
104
|
+
file: { type: 'string', description: 'Absolute path of an existing markdown, HTML, image or text file' },
|
|
105
|
+
key: { type: 'string', description: 'Card name: the same key replaces the card in place and keeps its file' },
|
|
106
|
+
},
|
|
107
|
+
required: ['title'],
|
|
108
|
+
},
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
return next(e)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
on('tool.call', { tool: TOOL }, async ($, e) => post($, e as unknown as ShowInput))
|
|
115
|
+
|
|
116
|
+
on('prompt.attachment', { type: 'skill_listing' }, async ($, e, next) => {
|
|
117
|
+
if (await terminal($)) return next(e)
|
|
118
|
+
return next({ ...e, text: dropSkillLine(e.text) })
|
|
119
|
+
})
|
|
120
|
+
}
|
|
@@ -22,6 +22,8 @@ End every spec with the reply line, because you usually need the result to conti
|
|
|
22
22
|
When you are done, or cannot finish, send the result to <your peer name> with the SendMessage tool, then stop.
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
A resumed session gets a new peer name, and the reply line still names the old one. After this session resumes, send each worker in `dispatch list` your new name with `SendMessage`.
|
|
26
|
+
|
|
25
27
|
`--handoff` is a skill argument that drops the reply line: the session owns the task, and the user follows it on the board. Keep it out of the `dispatch start` command.
|
|
26
28
|
|
|
27
29
|
## Track on the board (optional)
|
|
@@ -28,6 +28,8 @@ This session id is `${CLAUDE_SESSION_ID}`. `--session` defaults to it through `$
|
|
|
28
28
|
|
|
29
29
|
With no argument, run nothing on the board: show the user the table above.
|
|
30
30
|
|
|
31
|
+
An argument with no command name works on this session and its files. `open` and `preview` both mean `doc preview`, and with no target they mean the file this conversation is about. `open` focuses a session only as `session open`.
|
|
32
|
+
|
|
31
33
|
## Keep the board still
|
|
32
34
|
|
|
33
35
|
The user works in other windows while you run, so pick the quiet command. `doc link` and `pane add` add an entry the user opens when ready. `doc preview` is the one command that opens a modal on the user's screen: use it when the user asks to see something now.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: show
|
|
3
|
+
description: Show card guide for the cck overlay. Use before a show call that posts HTML (a chart, mockup or diagram), a mermaid diagram, or explains code (a call stack or tree).
|
|
4
|
+
argument-hint: '[explain|diagram|chart|mockup] [what to show]'
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Show cards
|
|
8
|
+
|
|
9
|
+
The `mcp__claude-code-kanban__show` tool exists only in a Claude Code session started in cck's terminal. Without it, tell the user that and stop.
|
|
10
|
+
|
|
11
|
+
An argument names a card kind from [Card kinds](#card-kinds) and what to show: read that kind's guide and post the card. With no kind, pick the one that makes the point best; with no topic, show the subject of this conversation.
|
|
12
|
+
|
|
13
|
+
## HTML contract
|
|
14
|
+
|
|
15
|
+
This applies to the `.html` file that a `kind: "html"` post names.
|
|
16
|
+
|
|
17
|
+
- Write a body fragment: no `<!doctype>`, `<html>`, `<head>` or `<body>`. The overlay wraps it in a sandboxed document. `<style>` and `<script>` work; the script has no access to the page around it.
|
|
18
|
+
- The card is about 360 to 640 px wide and sizes its height to the content. Keep the content in normal flow, without `position: fixed` or `100vh`.
|
|
19
|
+
- One chart or diagram per card, under an `<h2>` that says what to see. Keep it flat: solid fills and 1 px lines.
|
|
20
|
+
- Open links with `<a href="https://...">`; the overlay opens them in a new browser tab.
|
|
21
|
+
- Take every color and font from these variables, so the card follows the user's light or dark theme:
|
|
22
|
+
|
|
23
|
+
| Variable | Use |
|
|
24
|
+
|---|---|
|
|
25
|
+
| `--color-bg`, `--color-bg-subtle` | Page and panel background |
|
|
26
|
+
| `--color-text`, `--color-text-muted` | Body text, secondary text |
|
|
27
|
+
| `--color-border` | Lines, box outlines |
|
|
28
|
+
| `--color-accent` | The one thing to look at |
|
|
29
|
+
| `--color-info`, `--color-success`, `--color-warning`, `--color-danger` | Status |
|
|
30
|
+
| `--color-series-1` … `--color-series-8` | Chart series, in order |
|
|
31
|
+
| `--color-ramp-1` … `--color-ramp-5` | One-hue magnitude, least to most |
|
|
32
|
+
| `--font-sans`, `--font-mono` | Fonts |
|
|
33
|
+
|
|
34
|
+
## Card kinds
|
|
35
|
+
|
|
36
|
+
Any HTML that helps the user see the point is a good card: a comparison table, a checklist, a before and after, a diff, a small interactive widget, a mix of these. The HTML contract above is all it needs. Four kinds have their own guide; read it before you write that kind:
|
|
37
|
+
|
|
38
|
+
- Chart, stat tile or meter: [references/chart.md](references/chart.md)
|
|
39
|
+
- Mockup of a screen, dialog or form: [references/mockup.md](references/mockup.md)
|
|
40
|
+
- Diagram in SVG of a system, flow, states or layers: [references/diagram.md](references/diagram.md)
|
|
41
|
+
- Explain code (call stack, pseudocode, component or file tree, or a diff of one), in markdown: [references/explain.md](references/explain.md)
|
|
42
|
+
|
|
43
|
+
## Mermaid
|
|
44
|
+
|
|
45
|
+
The card is narrow. Use `flowchart TD`, short node labels and `subgraph` blocks, and split a big system map into several cards.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Notice
|
|
2
|
+
|
|
3
|
+
`diagram.md` and the files in `diagram/` are adapted from the diagram-design skill (https://github.com/cathrynlavery/diagram-design), under the MIT License:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2025 Cathryn Lavery
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Chart card
|
|
2
|
+
|
|
3
|
+
A chart in an HTML card. The card's CSP allows inline script only, so no chart library loads: draw bars with CSS or SVG, and lines with SVG.
|
|
4
|
+
|
|
5
|
+
## Choose the form before the colors
|
|
6
|
+
|
|
7
|
+
The data's job picks the form, and often the right form is not a chart.
|
|
8
|
+
|
|
9
|
+
| The data is | Post | Not |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| One current value, maybe with its change | A stat tile | A bar chart with one bar |
|
|
12
|
+
| 2 to 4 headline numbers | A row of stat tiles | A grouped bar chart |
|
|
13
|
+
| One ratio against a limit | A meter: a track with a fill | A pie with 2 slices |
|
|
14
|
+
|
|
15
|
+
When it is a chart, the reader's job picks the type:
|
|
16
|
+
|
|
17
|
+
| The reader must | Type | Color |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Compare sizes | Horizontal bars, sorted | One color, `--color-series-1` |
|
|
20
|
+
| See a trend over time | A line; an area for one series | One color |
|
|
21
|
+
| Tell series apart | Grouped or stacked bars, several lines | Series tokens in order |
|
|
22
|
+
| See that one item stands out | Bars or lines with one in `--color-accent`, the rest in `--color-border` | Accent and gray |
|
|
23
|
+
| See above or below a baseline | Bars that grow both ways from a zero line | `--color-success` and `--color-danger` only when up is good |
|
|
24
|
+
| See a magnitude across a grid | A heatmap | The ramp |
|
|
25
|
+
| See part of a whole | One stacked bar; at most 6 parts | Series tokens |
|
|
26
|
+
|
|
27
|
+
Horizontal bars suit the card best: long labels fit at the left and the bars use the width. Close values go in bars, because a pie hides small differences. One y-axis per chart: for two scales, post two charts or index both series to 100.
|
|
28
|
+
|
|
29
|
+
## Series
|
|
30
|
+
|
|
31
|
+
- Use the series tokens in order: the order keeps neighbors apart for color-blind readers.
|
|
32
|
+
- 1 to 3 series: color with direct labels is enough.
|
|
33
|
+
- 4 to 6: a legend, and label the lines at their ends.
|
|
34
|
+
- 7 or 8: the most the tokens allow. Past that, fold the smallest into "Other" or post a table. Never make up a ninth color.
|
|
35
|
+
- A series keeps its color when you filter or sort: color follows the item, not its rank.
|
|
36
|
+
- The ramp is for ordered values. Groups with no order (teams, endpoints) take series colors.
|
|
37
|
+
- Labels and values use `--color-text` or `--color-text-muted`; a small swatch or line key beside the text carries the series color.
|
|
38
|
+
|
|
39
|
+
## Marks
|
|
40
|
+
|
|
41
|
+
- Bars at most 24 px thick, with a 2 px gap between neighbors, rounded 4 px at the value end and square at the baseline. All bars grow from one baseline.
|
|
42
|
+
- Lines 2 px, round joins. End dots at least 8 px wide.
|
|
43
|
+
- An area fill is the series color at about 10% opacity.
|
|
44
|
+
- Gridlines and axes are solid 1 px `--color-border`, never dashed. Fewer is better: direct labels first, gridlines next.
|
|
45
|
+
- Separate touching marks with a gap in the background color, not with a stroke.
|
|
46
|
+
|
|
47
|
+
## Labels
|
|
48
|
+
|
|
49
|
+
- The `<h2>` says what to see ("p95 latency doubled after the deploy"), not what is plotted.
|
|
50
|
+
- Label the few values that matter: the last point, the extreme, the item the card is about. Put the value at the bar end or the line end.
|
|
51
|
+
- Round axis ticks (0, 1,000, 2,000) and use thousands separators.
|
|
52
|
+
- A label that does not fit inside a bar goes outside its end. Never clip it.
|
|
53
|
+
- Stat tile: a short label in sentence case, the value in sans, semibold, compact (`12.9K`, `$4.2M`), and an optional change against a named period (`+8% vs last week`), green or red only by whether up is good.
|
|
54
|
+
- `font-variant-numeric: tabular-nums` only for numbers in a column; a large single value uses normal figures.
|
|
55
|
+
|
|
56
|
+
## Fit the card
|
|
57
|
+
|
|
58
|
+
Size bars in `%`, or give SVG a `viewBox` and `width:100%`, so the chart scales with the card.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
For components and how they connect: a system overview, an integration map, trust zones.
|
|
4
|
+
|
|
5
|
+
- Group by tier, top to bottom: clients, services, stores.
|
|
6
|
+
- A zone (tier, network, trust boundary) is a rect with `rx` 8, `--color-bg-subtle` fill and a `--color-border` hairline, drawn first. Its name is a small mono label in its top left corner with 16 units of space above the first node. At most 3 zones; a dashed outline marks a trust boundary.
|
|
7
|
+
- 1 or 2 focal nodes: the main entry point or the main store.
|
|
8
|
+
- A two-bend path from (x1,y1) down to (x2,y2), with `m` halfway down:
|
|
9
|
+
|
|
10
|
+
```svg
|
|
11
|
+
<path class="edge" d="M x1,y1 V m-8 Q x1,m x1+8,m H x2-8 Q x2,m x2,m+8 V y2" marker-end="url(#d1-arrow)"/>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Flip the signs for the other directions. A line between nodes on one axis is a straight `V` or `H`.
|
|
15
|
+
- A vertical connection leaves the bottom edge and enters the top edge, not the sides.
|
|
16
|
+
- Where two lines must cross, the less important one hops over with a small arc: `H cx-8 a 8,8 0 0,1 16,0 H x2`.
|
|
17
|
+
- A call to an outside API may use `--color-info` for its line, when the diagram mixes internal and external calls.
|
|
18
|
+
- No two-headed arrows when one direction is the obvious one.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# ER
|
|
2
|
+
|
|
3
|
+
For a data model: tables, API resources, domain entities. A model with plain relationships is cheaper as a mermaid `erDiagram`; draw SVG when you need to group entities or mark the central one.
|
|
4
|
+
|
|
5
|
+
- At most 6 entities on a card; 2 columns of entities, relations between them.
|
|
6
|
+
- An entity is a box in two parts: a header with its name in sans on `--color-bg-subtle`, and a body with one field per line in mono. Mark the key `#id`, a foreign key `→ user_id`. Show only the fields the point needs.
|
|
7
|
+
- Boxes take the height of their fields; do not pad them to match.
|
|
8
|
+
- Relations are lines with the cardinality near each end in mono, 8 to 12 units off the box: `1`, `N`, `0..1`, `1..*`. Use one notation for both ends.
|
|
9
|
+
- An optional verb (`owns`, `belongs to`) sits on the middle of the line on a mask.
|
|
10
|
+
- Accent on the aggregate root or the entity the card is about.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Flow
|
|
2
|
+
|
|
3
|
+
For decision logic, triage, routing: "if this, then that".
|
|
4
|
+
|
|
5
|
+
- Node shapes:
|
|
6
|
+
- start and end: a pill, `rx` 16
|
|
7
|
+
- step: a rect, `rx` 6
|
|
8
|
+
- decision: a diamond with at most 3 exits; more exits means nested decisions
|
|
9
|
+
- merge: a filled dot, `r` 4, where branches meet again
|
|
10
|
+
- Label every edge out of a decision (`yes`, `no`, `timeout`). By habit "yes" goes down and "no" goes right, but the label is what counts.
|
|
11
|
+
- Accent goes on the happy path or on the one decision that matters most, not on every decision.
|
|
12
|
+
- A long chain of steps is a numbered list.
|
|
13
|
+
- On a narrow card keep side branches one column wide and return them to the main column.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Layers
|
|
2
|
+
|
|
3
|
+
For stacked levels: a tech stack, a cascade, a memory hierarchy, a context hierarchy. This is the type that suits the card best: it is tall by nature.
|
|
4
|
+
|
|
5
|
+
- 3 to 6 full-width bands of the same height (48 to 64 units), stacked with no gap and split by hairlines.
|
|
6
|
+
- Each band, left to right: an index tag in mono (`L3`, `APP`), the layer name in sans, a short note in muted mono at the right edge. On a 360 px card drop the note into a second line under the name.
|
|
7
|
+
- Fill: all `--color-bg` with hairlines, or alternate `--color-bg` and `--color-bg-subtle`. Pick one.
|
|
8
|
+
- Show direction once, outside the stack: a small arrow with a mono label (`requests ↓`).
|
|
9
|
+
- Accent on one layer: the bottleneck or the one under discussion.
|
|
10
|
+
- If the levels are not a hierarchy, it is an architecture or a swimlane.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Sequence
|
|
2
|
+
|
|
3
|
+
For requests and replies between actors over time: an API call path, an auth flow, an incident replay.
|
|
4
|
+
|
|
5
|
+
- Actors are boxes in one row at the top; at most 4 on a card (about 100 units apart in a 440 viewBox). A fifth actor makes the labels too small.
|
|
6
|
+
- Lifelines: dashed vertical lines in `--color-text-muted` under each actor. Time runs down.
|
|
7
|
+
- Messages are horizontal arrows, labeled above the line:
|
|
8
|
+
|
|
9
|
+
| Kind | Line | Head |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Call | solid, muted | filled |
|
|
12
|
+
| Return | dashed, muted | filled |
|
|
13
|
+
| Async, fire and forget | dashed, muted | open (a `polyline`, no fill) |
|
|
14
|
+
| The one result that matters | solid, accent | filled, accent |
|
|
15
|
+
|
|
16
|
+
- A self-call is a short U loop on the same lifeline, label on its right.
|
|
17
|
+
- An activation bar (8 units wide, `--color-bg-subtle`, hairline) shows who holds control, only when that matters.
|
|
18
|
+
- A branch goes in one frame: a rect over the lifelines it spans, with a tab at its top left (`ALT`, `OPT`, `LOOP`) in mono and the guard (`[token valid]`) under it. `ALT` splits its regions with a dashed line. At most one frame, no nesting.
|
|
19
|
+
- At most 12 messages. Past that, post the overview and put the detail on a second card.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# State
|
|
2
|
+
|
|
3
|
+
For finite states: order status, connection lifecycle, job status, a wizard.
|
|
4
|
+
|
|
5
|
+
- States are rects with `rx` 8, name in sans.
|
|
6
|
+
- Start: a filled dot, `r` 6. End: a ring, `r` 8, around a filled dot, `r` 5.
|
|
7
|
+
- Every transition has a label in mono: `event [guard] / action`, each part only when it says something.
|
|
8
|
+
- A self-transition loops over the top of its state.
|
|
9
|
+
- Run top to bottom; reorder states before you let transitions cross.
|
|
10
|
+
- A transition from every state (timeout, cancel) is one note under the diagram, `* → Failed on timeout`, not an arrow from each state.
|
|
11
|
+
- Accent on the state the reader should notice, usually the failure state or the done state.
|
|
12
|
+
- More transitions than twice the states means two machines: post two cards.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Swimlane
|
|
2
|
+
|
|
3
|
+
For a process that passes between people, teams or systems.
|
|
4
|
+
|
|
5
|
+
- On a card, lanes are columns, one per actor, at most 4, with time running down. Rows of lanes run sideways and do not fit.
|
|
6
|
+
- Each lane has a mono label at its top. Hairlines split the lanes.
|
|
7
|
+
- A step is a rect in the lane of the actor that does it, never across two lanes.
|
|
8
|
+
- Handoffs (lines that cross a lane border) are the edges that matter. Accent the one that adds the most delay or coupling.
|
|
9
|
+
- A lane with one step is fine; do not pad lanes to match.
|
|
10
|
+
- Order the steps so the flow goes mostly down; a line that zigzags between lanes means the order is wrong.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Timeline
|
|
2
|
+
|
|
3
|
+
For events in time: releases, milestones, an incident, a roadmap.
|
|
4
|
+
|
|
5
|
+
- On a card the axis runs down: a hairline at the left, dates in mono to its left, events to its right. A horizontal axis fits only 4 or 5 short events.
|
|
6
|
+
- An event is a filled dot, `r` 4, on the axis, with its label beside it. A milestone is an accent dot, `r` 6, with a bold label.
|
|
7
|
+
- Space events by real time. If one stretch is crowded and another empty, break the axis with a visible gap mark rather than fake even spacing.
|
|
8
|
+
- Name the unit of the axis (days, sprints, versions).
|
|
9
|
+
- An incident timeline can color its dots by status (`--color-danger` for the outage start, `--color-success` for the recovery), and nothing else.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Tree
|
|
2
|
+
|
|
3
|
+
For parent and children: a dependency tree, a taxonomy, a breakdown, an ownership chart.
|
|
4
|
+
|
|
5
|
+
- Root at the top. At most 4 levels and 4 children per level on a card; past that, split it, or turn the tree on its side as an indented list with elbow lines on the left, which fits a narrow card well.
|
|
6
|
+
- Nodes are rects with `rx` 6, 32 to 48 units tall, at most two widths.
|
|
7
|
+
- Lines are elbows: a short drop from the parent, a horizontal bus over the children, a short drop into each child's top edge. Hairline, muted.
|
|
8
|
+
- A leaf can have a thinner stroke, or let its position say it.
|
|
9
|
+
- Accent on one node: the root or one key leaf, not both.
|
|
10
|
+
- No level skipped: a parent links only to its own children.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Diagram card
|
|
2
|
+
|
|
3
|
+
An SVG diagram in an HTML card, for a picture that mermaid lays out badly: layers, zones, lanes, a timeline, or one node that must stand out. For a plain flowchart, sequence or ER sketch, a mermaid block in a markdown card is cheaper; use this only when layout or emphasis carries the meaning.
|
|
4
|
+
|
|
5
|
+
## Decide first
|
|
6
|
+
|
|
7
|
+
- Would a table or three sentences say the same? Then write those.
|
|
8
|
+
- Pick one type from the table, then read its file before you draw.
|
|
9
|
+
- Delete before you add. Every node is a distinct idea: two nodes that always travel together are one. Every line carries information: if the layout already shows the link, drop the line.
|
|
10
|
+
- More than 9 nodes is two cards: an overview and a detail.
|
|
11
|
+
|
|
12
|
+
| Showing | Type | File |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Decision logic with branches | Flow | `diagram/flow.md` |
|
|
15
|
+
| Messages between actors over time | Sequence | `diagram/sequence.md` |
|
|
16
|
+
| States and the events that move between them | State | `diagram/state.md` |
|
|
17
|
+
| Stacked levels of abstraction | Layers | `diagram/layers.md` |
|
|
18
|
+
| Components, connections, trust zones | Architecture | `diagram/architecture.md` |
|
|
19
|
+
| Parent and children | Tree | `diagram/tree.md` |
|
|
20
|
+
| A process with handoffs between teams | Swimlane | `diagram/swimlane.md` |
|
|
21
|
+
| Events in time | Timeline | `diagram/timeline.md` |
|
|
22
|
+
| Entities, fields, relationships | ER | `diagram/er.md` |
|
|
23
|
+
|
|
24
|
+
Bars, lines, scatter and Gantt are charts: read `chart.md`.
|
|
25
|
+
|
|
26
|
+
## Fit the card
|
|
27
|
+
|
|
28
|
+
Content wider than the card scrolls sideways, which reads badly; content taller than the card scrolls down, which reads fine.
|
|
29
|
+
|
|
30
|
+
- Draw for a narrow card: viewBox width 400 to 480, top to bottom. A wide left-to-right map turns its 12 px labels into 8 px at the default size.
|
|
31
|
+
- Scale with the card: `<svg viewBox="0 0 440 H" style="width:100%;max-width:660px;height:auto">`. Never a fixed `width`.
|
|
32
|
+
- Text at least 12 viewBox units, so it stays readable at 360 px.
|
|
33
|
+
- The title goes in the `<h2>` above the SVG, not inside it.
|
|
34
|
+
|
|
35
|
+
## Colors
|
|
36
|
+
|
|
37
|
+
Presentation attributes do not take `var()`, so color the SVG through classes in a `<style>` block. Then the diagram follows the user's theme switch with no script.
|
|
38
|
+
|
|
39
|
+
| Role | Token |
|
|
40
|
+
|---|---|
|
|
41
|
+
| Canvas, node mask | `--color-bg` |
|
|
42
|
+
| Container, zone fill | `--color-bg-subtle` |
|
|
43
|
+
| Node name, main stroke | `--color-text` |
|
|
44
|
+
| Sublabel, default arrow, lifeline | `--color-text-muted` |
|
|
45
|
+
| Hairline, zone outline | `--color-border` |
|
|
46
|
+
| Focal node or path, 1 or 2 per diagram | `--color-accent` |
|
|
47
|
+
| Status meaning only | `--color-info`, `--color-success`, `--color-warning`, `--color-danger` |
|
|
48
|
+
|
|
49
|
+
Make tints with `color-mix(in srgb, var(--color-accent) 12%, var(--color-bg))`, not opacity, so lines behind a node do not show through.
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<style>
|
|
53
|
+
.d text { font: 12px var(--font-sans); fill: var(--color-text); }
|
|
54
|
+
.d .sub { font: 12px var(--font-mono); fill: var(--color-text-muted); }
|
|
55
|
+
.d .node { fill: var(--color-bg); stroke: var(--color-text); stroke-width: 1; }
|
|
56
|
+
.d .store { fill: var(--color-bg-subtle); stroke: var(--color-text-muted); }
|
|
57
|
+
.d .focal { fill: color-mix(in srgb, var(--color-accent) 12%, var(--color-bg)); stroke: var(--color-accent); }
|
|
58
|
+
.d .edge { fill: none; stroke: var(--color-text-muted); stroke-width: 1.2; }
|
|
59
|
+
.d .edge.hot { stroke: var(--color-accent); }
|
|
60
|
+
.d .dash { stroke-dasharray: 4 3; }
|
|
61
|
+
.d .head { fill: var(--color-text-muted); }
|
|
62
|
+
.d .label-mask { fill: var(--color-bg); }
|
|
63
|
+
</style>
|
|
64
|
+
<svg class="d" viewBox="0 0 440 300" style="width:100%;max-width:660px;height:auto" role="img" aria-labelledby="d1-t">
|
|
65
|
+
<title id="d1-t">Order service writes to the queue</title>
|
|
66
|
+
<defs>
|
|
67
|
+
<marker id="d1-arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
|
|
68
|
+
<polygon class="head" points="0 0, 8 3, 0 6" />
|
|
69
|
+
</marker>
|
|
70
|
+
</defs>
|
|
71
|
+
<!-- edges first, then nodes -->
|
|
72
|
+
</svg>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Give each marker and title an id with a per-card prefix (`d1-`), so two SVGs in one card do not clash.
|
|
76
|
+
|
|
77
|
+
## Shapes and lines
|
|
78
|
+
|
|
79
|
+
- Node: `rx` 6, name in `--font-sans`, a technical sublabel (port, path, type) in `--font-mono`. Names in mono read as noise.
|
|
80
|
+
- Node kinds by fill and stroke, not by color: plain step `.node`, store `.store`, external a thin stroke, optional or async a dashed stroke, focal `.focal`.
|
|
81
|
+
- Lines go straight or bend at right angles with a rounded corner (radius 8), also between nodes that are not on one axis.
|
|
82
|
+
- Draw edges before nodes, so nodes cover the line ends.
|
|
83
|
+
- An edge label sits horizontal on an opaque `.label-mask` rect, 6 to 10 units off its line, at most 14 characters.
|
|
84
|
+
- Each line has its own path and attach point, 12 units from the next.
|
|
85
|
+
- Corner radius at most 8.
|
|
86
|
+
- A legend, when the diagram needs one, is a row below the diagram, not inside it.
|
|
87
|
+
- Coordinates and sizes on a 4-unit grid keep the spacing even.
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# Explain card
|
|
2
|
+
|
|
3
|
+
A markdown card that shows how code works: what calls what, what a function decides, where things live, or what a change moves. Post `kind: "markdown"`; the board renders the fences below.
|
|
4
|
+
|
|
5
|
+
## Make one point
|
|
6
|
+
|
|
7
|
+
Each card makes one point about the code under discussion. Write the point as a sentence or two, then the view that proves it. Pick the smallest view that makes the point clear; add a second view to the card only when it shows what the first cannot.
|
|
8
|
+
|
|
9
|
+
| Showing | View | Fence |
|
|
10
|
+
|---|---|---|
|
|
11
|
+
| Runtime flow: who calls whom | Call stack | `callstack` |
|
|
12
|
+
| What a function decides | Pseudocode | `text` |
|
|
13
|
+
| UI structure, state and module boundaries | Component tree | `tsx` |
|
|
14
|
+
| Which file owns what | File tree | `text` |
|
|
15
|
+
| Messages between parts over time | Sequence | `mermaid` |
|
|
16
|
+
| What a change adds, removes or moves | A diff of the view above | see [Diff](#diff) |
|
|
17
|
+
|
|
18
|
+
Keep only the calls, files, props and states the point needs, with real names from the code. Give the card a `key` that names the topic; post a follow-up view, such as the diff after the fix, with the same key so it replaces the card.
|
|
19
|
+
|
|
20
|
+
## Call stack
|
|
21
|
+
|
|
22
|
+
The board draws the tree lines, links, focus and folds from this notation:
|
|
23
|
+
|
|
24
|
+
```callstack
|
|
25
|
+
handleCheckout src/routes/checkout.ts:24
|
|
26
|
+
validateCart throws on an empty cart
|
|
27
|
+
placeOrder * src/orders/place.ts:40
|
|
28
|
+
chargeCard src/payments/charge.ts:31
|
|
29
|
+
~ 2 SDK frames
|
|
30
|
+
PaymentsClient.charge node_modules/pay-sdk/client.js:112
|
|
31
|
+
HttpClient.request node_modules/pay-sdk/http.js:58
|
|
32
|
+
+ sendReceipt src/email/receipt.ts:9
|
|
33
|
+
- logOrder src/orders/log.ts:5
|
|
34
|
+
onPaymentWebhook src/routes/webhooks.ts:58
|
|
35
|
+
markOrderPaid src/orders/status.ts:22
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- The fence tag is `callstack`.
|
|
39
|
+
- Caller on top. Indent each callee 2 spaces under its caller; the board turns the spaces into tree lines. Several roots are fine.
|
|
40
|
+
- One frame per line: the function or method name as one identifier, spelled as in the code.
|
|
41
|
+
- The note goes after 2 or more spaces: a `path:line` relative to the project root, which the board links, or a few words. Line the notes up in one column.
|
|
42
|
+
- A `*` after the name, with one space, marks the frame to look at. One per stack.
|
|
43
|
+
- `+` or `-` in the first column marks a frame the change adds or removes. In a stack with any `+` or `-`, every other line starts with one space.
|
|
44
|
+
|
|
45
|
+
### Folds
|
|
46
|
+
|
|
47
|
+
A `~ N <what> frames` line stands for frames the reader can skip, such as framework, library or runtime code. It sits where those frames sit: under the frame that calls them, or at the top for framework callers above a handler.
|
|
48
|
+
|
|
49
|
+
- With frames indented under it, the line is a fold: the board shows it closed, and the reader clicks it to open.
|
|
50
|
+
- A fold that holds the `*` frame or a `+` or `-` frame starts open, so the point stays on screen.
|
|
51
|
+
- Folds nest: library frames that call runtime frames get a `~` each.
|
|
52
|
+
- With nothing under it, the line is a note that frames were left out. Write the frames out only when the reader may need them.
|
|
53
|
+
|
|
54
|
+
## Pseudocode
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
placeOrder(cart)
|
|
58
|
+
if any item is out of stock
|
|
59
|
+
return "sold out"
|
|
60
|
+
charge the card
|
|
61
|
+
if the charge fails
|
|
62
|
+
release the stock
|
|
63
|
+
send the receipt
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Component tree
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
<CheckoutPage> (src/routes/checkout.tsx)
|
|
70
|
+
useCart()
|
|
71
|
+
<OrderSummary>
|
|
72
|
+
<PayButton> (packages/ui)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## File tree
|
|
76
|
+
|
|
77
|
+
The one view drawn with box characters:
|
|
78
|
+
|
|
79
|
+
```text
|
|
80
|
+
src/
|
|
81
|
+
├── routes/ # HTTP handlers
|
|
82
|
+
├── orders/ # owns order state
|
|
83
|
+
└── payments/ # talks to the card provider
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Diff
|
|
87
|
+
|
|
88
|
+
Draw a change in the shape of the view it changes: a component tree diff for a component change, a file tree diff for a move. Mark each line with `+`, `-` or a space in the first column. A call stack takes the marks inside its `callstack` fence; every other view goes in a `diff` fence:
|
|
89
|
+
|
|
90
|
+
```diff
|
|
91
|
+
<CheckoutPage>
|
|
92
|
+
useCart()
|
|
93
|
+
<OrderSummary>
|
|
94
|
+
+ <PromoCodeInput />
|
|
95
|
+
<PayButton>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Show the whole block without marks when most of it is new, or when a diff would hide the order or the owner of each part.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Mockup card
|
|
2
|
+
|
|
3
|
+
A wireframe in an HTML card: a screen, a dialog, a form or a component, to agree on layout and wording before code.
|
|
4
|
+
|
|
5
|
+
## Content
|
|
6
|
+
|
|
7
|
+
- Real labels and real copy from the task: "Delete 3 sessions?", not "Lorem ipsum" or "Button".
|
|
8
|
+
- Plain boxes in place of logos, brand names and product chrome. A gray block (`--color-bg-subtle`) with a mono caption stands in for an image, chart or map.
|
|
9
|
+
- One screen or one state per card. For a flow, post one card per step under one `key` prefix, or show 2 or 3 states side by side when they fit.
|
|
10
|
+
- Mark open questions with numbered callouts: a small circle in `--color-accent` with a number, and the notes as a list under the sketch.
|
|
11
|
+
|
|
12
|
+
## Building blocks
|
|
13
|
+
|
|
14
|
+
The card already styles `button`, `button.primary`, `input`, `select`, `textarea`, `table` and headings from the tokens. Use them as they are.
|
|
15
|
+
|
|
16
|
+
```html
|
|
17
|
+
<style>
|
|
18
|
+
.m { border: 1px solid var(--color-border); border-radius: 8px; overflow: hidden; }
|
|
19
|
+
.m-bar { display: flex; gap: 8px; align-items: center; padding: 8px 12px; background: var(--color-bg-subtle); border-bottom: 1px solid var(--color-border); }
|
|
20
|
+
.m-body { padding: 12px; display: grid; gap: 8px; }
|
|
21
|
+
.m-img { background: var(--color-bg-subtle); border: 1px dashed var(--color-border); border-radius: 6px; min-height: 64px; display: grid; place-items: center; font: 11px var(--font-mono); color: var(--color-text-muted); }
|
|
22
|
+
.m-note { display: inline-grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--color-accent); color: #fff; font: 600 11px var(--font-sans); }
|
|
23
|
+
</style>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Fit the card
|
|
27
|
+
|
|
28
|
+
- A sketch narrower than the card sits centered (`margin-inline: auto`).
|
|
29
|
+
- A phone screen fits at real size, about 360 px. A desktop screen does not: sketch the part under discussion (one panel, the toolbar, the dialog), not the whole window.
|
|
30
|
+
- Scripts may toggle a state (open a menu, switch a tab) to show the interaction. Keep it to a few lines; the card has no storage and no network.
|