chiltepin 0.47.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/LICENSE +21 -0
- package/README.md +249 -0
- package/dist/bin.js +3582 -0
- package/dist/bin.js.map +1 -0
- package/package.json +93 -0
- package/templates/chiltepin.config.json +5 -0
- package/templates/demo.md +2161 -0
- package/templates/docs/getting-started.md +155 -0
- package/templates/docs/tutorial.md +559 -0
- package/templates/skill/SKILL.md +172 -0
- package/templates/skill/reference/blocks/INDEX.md +141 -0
- package/templates/skill/reference/blocks/agentic.md +63 -0
- package/templates/skill/reference/blocks/algorithms.md +49 -0
- package/templates/skill/reference/blocks/api.md +40 -0
- package/templates/skill/reference/blocks/architecture.md +94 -0
- package/templates/skill/reference/blocks/business.md +70 -0
- package/templates/skill/reference/blocks/charts-overviews.md +74 -0
- package/templates/skill/reference/blocks/data-model.md +34 -0
- package/templates/skill/reference/blocks/design-system.md +50 -0
- package/templates/skill/reference/blocks/flows.md +74 -0
- package/templates/skill/reference/blocks/narrative.md +65 -0
- package/templates/skill/reference/blocks/planning.md +74 -0
- package/templates/skill/reference/blocks/quality.md +43 -0
- package/templates/skill/reference/blocks/tables-data.md +55 -0
- package/templates/skill/reference/check.md +62 -0
- package/templates/skill/reference/decks.md +198 -0
- package/templates/skill/reference/exemplars/adr.md +87 -0
- package/templates/skill/reference/exemplars/agent-system.md +113 -0
- package/templates/skill/reference/exemplars/api-reference.md +110 -0
- package/templates/skill/reference/exemplars/backend-arch.md +117 -0
- package/templates/skill/reference/exemplars/data-pipeline.md +107 -0
- package/templates/skill/reference/exemplars/frontend-arch.md +93 -0
- package/templates/skill/reference/exemplars/incident-postmortem.md +93 -0
- package/templates/skill/reference/exemplars/migration-plan.md +95 -0
- package/templates/skill/reference/exemplars/onboarding.md +78 -0
- package/templates/skill/reference/exemplars/product-spec.md +81 -0
- package/templates/skill/reference/intake.md +140 -0
- package/templates/skill/reference/mermaid.md +216 -0
- package/templates/skill/reference/organizing.md +118 -0
- package/templates/skill/reference/patterns-design.md +59 -0
- package/templates/skill/reference/patterns.md +167 -0
- package/templates/skill/reference/recipes.md +153 -0
- package/templates/skill/reference/style-ste.md +119 -0
- package/templates/skill/reference/system-design.md +161 -0
- package/templates/skill/reference/writing.md +132 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Messaging and event patterns — which blocks draw them
|
|
2
|
+
|
|
3
|
+
Part of the **chiltepin** skill (the hub is `SKILL.md`, one folder up). Read
|
|
4
|
+
this when the request is about events, queues, streams, fan-out, or making a
|
|
5
|
+
write reliable across two systems. Each pattern names the reader question,
|
|
6
|
+
the block stack that answers it, and the trap. Fields: `chiltepin block <type>`.
|
|
7
|
+
|
|
8
|
+
Three rules hold for every pattern here:
|
|
9
|
+
|
|
10
|
+
- Topology at rest is a `block` with `preset: event`. Producers are `kind:
|
|
11
|
+
producer`, subscribers `kind: consumer`, brokers `kind: topic` (fan-out)
|
|
12
|
+
or `kind: queue` (one taker), streams `kind: stream`. The single
|
|
13
|
+
`producer` takes the accent; put the fan-out in one column so the topic
|
|
14
|
+
reads as the hub.
|
|
15
|
+
- One event's contract is an `eventcontract`, never a `table` row: it
|
|
16
|
+
carries producers, consumers, delivery, ordering, the partition `key`,
|
|
17
|
+
and retention, which is exactly what a consumer needs to be safe.
|
|
18
|
+
- Time and failure are `sequence` (async arrows `-->` for the broker hop,
|
|
19
|
+
an `alt` frame for the failure branch) or `flow` (retry loops, decisions).
|
|
20
|
+
A `block` shows who is wired to whom; it cannot show a retry.
|
|
21
|
+
|
|
22
|
+
## Publish / subscribe (fan-out to many)
|
|
23
|
+
|
|
24
|
+
Question: when X happens, who reacts, and does the producer know them?
|
|
25
|
+
Stack: `block` (`preset: event`) → `eventcontract` for the event → prose on
|
|
26
|
+
delivery and ordering. Trap: a `sequence` with one arrow per subscriber
|
|
27
|
+
hides the point, which is that the publisher has no arrows to them.
|
|
28
|
+
|
|
29
|
+
```block
|
|
30
|
+
preset: event
|
|
31
|
+
groups:
|
|
32
|
+
- { id: subs, col: 3, row: 1, cols: 1, rows: 3, label: Subscribers }
|
|
33
|
+
nodes:
|
|
34
|
+
- { id: orders, col: 1, row: 2, kind: producer, name: Orders, tech: order.placed }
|
|
35
|
+
- { id: t, col: 2, row: 2, kind: topic, name: order-events, tech: Kafka }
|
|
36
|
+
- { id: mail, col: 3, row: 1, kind: consumer, name: Email }
|
|
37
|
+
- { id: search, col: 3, row: 2, kind: consumer, name: Search index }
|
|
38
|
+
- { id: audit, col: 3, row: 3, kind: consumer, name: Audit log }
|
|
39
|
+
edges:
|
|
40
|
+
- orders -> t: publish
|
|
41
|
+
- t -> mail
|
|
42
|
+
- t -> search
|
|
43
|
+
- t -> audit
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Competing consumers (one taker wins)
|
|
47
|
+
|
|
48
|
+
Question: how does work spread across N workers, and how many times is a
|
|
49
|
+
message handled? Stack: `block` (`preset: event`, a `queue` not a `topic`,
|
|
50
|
+
the workers in one group, dashed edges to the workers that did not take
|
|
51
|
+
the message) → `spec` for at-least-once and idempotency rules. Trap:
|
|
52
|
+
drawing it as pub/sub; a queue delivers each message once.
|
|
53
|
+
|
|
54
|
+
## Partitioned log and consumer group (streams)
|
|
55
|
+
|
|
56
|
+
Question: how does the stream scale, and what keeps order? Stack: `block`
|
|
57
|
+
(partitions as `queue` nodes inside a `Topic` group, consumers in a
|
|
58
|
+
`Consumer group` group, the partition key on the producer edge) → prose on
|
|
59
|
+
what the key is and what happens when a consumer joins or leaves. Trap: a
|
|
60
|
+
`sequence`; the question is placement, not time.
|
|
61
|
+
|
|
62
|
+
```block
|
|
63
|
+
preset: event
|
|
64
|
+
groups:
|
|
65
|
+
- { id: t, col: 2, row: 1, cols: 1, rows: 3, label: orders topic (3 partitions) }
|
|
66
|
+
- { id: cg, col: 3, row: 1, cols: 1, rows: 3, label: billing consumer group }
|
|
67
|
+
nodes:
|
|
68
|
+
- { id: prod, col: 1, row: 2, kind: producer, name: Orders API }
|
|
69
|
+
- { id: p0, col: 2, row: 1, kind: queue, name: partition 0 }
|
|
70
|
+
- { id: p1, col: 2, row: 2, kind: queue, name: partition 1 }
|
|
71
|
+
- { id: p2, col: 2, row: 3, kind: queue, name: partition 2 }
|
|
72
|
+
- { id: c0, col: 3, row: 1, kind: consumer, name: billing-1 }
|
|
73
|
+
- { id: c1, col: 3, row: 2, kind: consumer, name: billing-2 }
|
|
74
|
+
- { id: c2, col: 3, row: 3, kind: consumer, name: billing-3 }
|
|
75
|
+
edges:
|
|
76
|
+
- prod -> p0: "key = order_id"
|
|
77
|
+
- prod -> p1
|
|
78
|
+
- prod -> p2
|
|
79
|
+
- p0 -> c0
|
|
80
|
+
- p1 -> c1
|
|
81
|
+
- p2 -> c2
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Event-driven backbone (many producers, many consumers)
|
|
85
|
+
|
|
86
|
+
Question: what is the shape of the whole event system? Stack: `block` in
|
|
87
|
+
`layers` mode (Producers · Backbone · Consumers) with one `topic` node in
|
|
88
|
+
the middle band → `table` of topics × producer × consumers × retention.
|
|
89
|
+
Trap: drawing every topic as a node; past four topics the table carries
|
|
90
|
+
it and the diagram shows the bands.
|
|
91
|
+
|
|
92
|
+
## Outbox (reliable publish after a commit)
|
|
93
|
+
|
|
94
|
+
Question: how do we never lose an event when the commit succeeds and the
|
|
95
|
+
publish fails? Stack: `sequence` (API → DB writes row and outbox in one
|
|
96
|
+
transaction; relay polls outbox → broker; `alt` for the broker being
|
|
97
|
+
down) → `state` for the outbox row (pending → published → failed) → `spec`
|
|
98
|
+
for the invariants (same transaction, at-least-once, consumer idempotent).
|
|
99
|
+
Trap: a `block` alone; the pattern is an ordering of writes, so it needs
|
|
100
|
+
time.
|
|
101
|
+
|
|
102
|
+
## Dead-letter queue and retry (poison messages)
|
|
103
|
+
|
|
104
|
+
Question: what happens to a message that keeps failing, and who looks at
|
|
105
|
+
it? Stack: `flow` (consume → process → ok / retry with backoff / after N
|
|
106
|
+
to the DLQ, `kind: error` on the DLQ edge) → `block` (`queue` → consumer
|
|
107
|
+
→ `DLQ` queue) → `table` of failure classes × action × owner. Trap: a
|
|
108
|
+
`sequence`; the loop and the threshold are decisions, not messages.
|
|
109
|
+
|
|
110
|
+
## CQRS (separate read and write models)
|
|
111
|
+
|
|
112
|
+
Question: why are reads and writes different shapes, and how does a write
|
|
113
|
+
reach the read side? Stack: `block` (command side → write store → events
|
|
114
|
+
→ projector → read store → query side, `dfd` also works) → `sequence` for
|
|
115
|
+
one write and the eventual read → prose on the consistency lag and what
|
|
116
|
+
the UI does about it. Trap: an `erd` of the read model; the reader asked
|
|
117
|
+
for the split, not the columns.
|
|
118
|
+
|
|
119
|
+
## Event sourcing (append-only log)
|
|
120
|
+
|
|
121
|
+
Question: where is the truth, and how is current state rebuilt? Stack:
|
|
122
|
+
`block` (commands → aggregate → event store, `replay` dashed back,
|
|
123
|
+
projections subscribing) → `eventcontract` for one event → `spec` for
|
|
124
|
+
replay, snapshots, and schema evolution. Trap: a `state` machine of the
|
|
125
|
+
aggregate; the pattern is about storage, not lifecycle.
|
|
126
|
+
|
|
127
|
+
## Saga (multi-service undo)
|
|
128
|
+
|
|
129
|
+
Question: what happens when step three of five fails after steps one and
|
|
130
|
+
two committed? Stack: `saga` (forward steps, compensation under each,
|
|
131
|
+
`failAt`) → `sequence` only if the message order between services is the
|
|
132
|
+
question → `table` of steps × compensation × idempotency key. Trap: a
|
|
133
|
+
`flow`; a saga's shape is steps with their undo, which `flow` cannot say.
|
|
134
|
+
|
|
135
|
+
## Scatter-gather
|
|
136
|
+
|
|
137
|
+
Question: how does one request fan out to N workers and come back as one
|
|
138
|
+
answer? Stack: `block` (coordinator → workers group → aggregator) →
|
|
139
|
+
`sequence` with a `par` frame for the parallel calls and the timeout
|
|
140
|
+
branch → `spec` for the partial-result rule. Trap: `flow`; the parallelism
|
|
141
|
+
is the point and `par` draws it.
|
|
142
|
+
|
|
143
|
+
## Backpressure, retry, and circuit breaker
|
|
144
|
+
|
|
145
|
+
Question: what does the system do when a downstream slows or fails?
|
|
146
|
+
Stack: `state` for the breaker (closed → open → half-open) or `flow` for
|
|
147
|
+
retry with backoff and the give-up exit → `spec` for the numbers
|
|
148
|
+
(timeout, attempts, backoff, jitter, trip threshold) → `sequence` only for
|
|
149
|
+
the one call that shows the breaker opening. Trap: prose only; the
|
|
150
|
+
numbers are the contract, and `spec` holds them.
|
|
151
|
+
|
|
152
|
+
## Change data capture and webhooks (events out of a store or to a partner)
|
|
153
|
+
|
|
154
|
+
Question: how do changes leave the database, or reach a partner, in
|
|
155
|
+
order and exactly once as far as they can tell? Stack: `dfd` (table →
|
|
156
|
+
log → connector → topic → consumers) or `sequence` (producer → partner
|
|
157
|
+
endpoint, signed, retried, `alt` for 5xx) → `eventcontract` for the
|
|
158
|
+
payload → `spec` for signing, retry, and replay. Trap: an `endpoint`
|
|
159
|
+
block for a webhook; the partner's endpoint is not ours to document.
|
|
160
|
+
|
|
161
|
+
## Idempotency
|
|
162
|
+
|
|
163
|
+
Question: what happens when the same message or request arrives twice?
|
|
164
|
+
Stack: `sequence` with the duplicate as a second message and an `alt`
|
|
165
|
+
frame (key seen → return stored result) → `spec` for the key, its scope,
|
|
166
|
+
and its TTL → `state` when the record itself moves (received → processed).
|
|
167
|
+
Trap: a `callout` only; the reader needs the exact key and window.
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Composition recipes
|
|
2
|
+
|
|
3
|
+
Part of the **chiltepin** skill (the hub is `SKILL.md`, one folder up).
|
|
4
|
+
These are worked examples of composition, not forms to fill in. Two different
|
|
5
|
+
systems must not produce structurally identical docs.
|
|
6
|
+
|
|
7
|
+
Start from the reader
|
|
8
|
+
questions, not from a recipe. Keep a block only if your system raises its
|
|
9
|
+
question, and drop it if not. Add a block these stacks never mention when your
|
|
10
|
+
system needs it. Fields: `chiltepin block <type>`; discriminators: the family files.
|
|
11
|
+
|
|
12
|
+
Each recipe: the reader questions → the block stack in document order → the
|
|
13
|
+
alternatives rejected, and why. The stack notes what each block carries and
|
|
14
|
+
what the prose around it carries. Prose carries why, tradeoff, and consequence — never a
|
|
15
|
+
description of the block beside it.
|
|
16
|
+
|
|
17
|
+
## Backend architecture
|
|
18
|
+
|
|
19
|
+
Reader questions: What are the boundaries? · What calls what on the critical
|
|
20
|
+
path? · Who owns what?
|
|
21
|
+
|
|
22
|
+
1. `meta` — the system's name and its one-line job.
|
|
23
|
+
2. Prose — why the system exists; the one constraint that shaped the design.
|
|
24
|
+
3. `c4` — ours vs external, one level only. Prose after: what the boundary
|
|
25
|
+
decision costs, not what the picture already shows.
|
|
26
|
+
4. `cluster` or `block` (`preset: infra`) — the deployment topology. Prose
|
|
27
|
+
after: which parts fail independently.
|
|
28
|
+
5. `sequence` — the one request path that pays the bills, with its failure
|
|
29
|
+
branch. Prose after: the consequence a client can rely on.
|
|
30
|
+
6. `table` — service × responsibility × owner.
|
|
31
|
+
7. `callout` — the invariant that must not break.
|
|
32
|
+
|
|
33
|
+
Rejected: `uml` (class detail is the code's job) · `graph` (no boundaries —
|
|
34
|
+
a backend doc is about what contains what).
|
|
35
|
+
|
|
36
|
+
## AI / agent architecture
|
|
37
|
+
|
|
38
|
+
Reader questions: What does the loop do? · What can it call? · What fills the
|
|
39
|
+
window? · What does a real run look like?
|
|
40
|
+
|
|
41
|
+
1. `meta` — the agent's name and the task it owns.
|
|
42
|
+
2. Prose — the task delegated to the agent; where a human stays in the loop.
|
|
43
|
+
3. `agentloop` — environment, tools, memory, stop condition.
|
|
44
|
+
4. `context` — the window budget. Prose after: what gets evicted first, and
|
|
45
|
+
why that is safe.
|
|
46
|
+
5. `prompt` — the contract the model is held to.
|
|
47
|
+
6. `sequence` — one turn end-to-end, including a tool failure.
|
|
48
|
+
7. `trace` — one real transcript, evidence the loop behaves as drawn.
|
|
49
|
+
8. `callout` — the safety boundary the agent cannot cross.
|
|
50
|
+
|
|
51
|
+
Rejected: `flow` (the loop is the primitive here, not a branch chart).
|
|
52
|
+
|
|
53
|
+
## Frontend architecture
|
|
54
|
+
|
|
55
|
+
Reader questions: What are the modules? · What states can the UI be in? ·
|
|
56
|
+
Where does data come from?
|
|
57
|
+
|
|
58
|
+
1. `meta` — the app and its rendering model in one line.
|
|
59
|
+
2. Prose — the rendering-model decision (SSR/SPA/islands) and its cost.
|
|
60
|
+
3. `frontend` or `felogic` — the module graph. Prose after: the dependency
|
|
61
|
+
rule the graph must keep.
|
|
62
|
+
4. `wireframe` — the one screen that matters.
|
|
63
|
+
5. `state` — the UI states, error and empty included. Prose after: which
|
|
64
|
+
state users actually sit in most.
|
|
65
|
+
6. `sequence` — the data-fetch path.
|
|
66
|
+
7. `table` — the routes.
|
|
67
|
+
|
|
68
|
+
Rejected: `c4` (usually one container — a boundary diagram with one box says
|
|
69
|
+
nothing).
|
|
70
|
+
|
|
71
|
+
## Data flow / pipeline
|
|
72
|
+
|
|
73
|
+
Reader questions: Where does data come from and go? · What shape is it at
|
|
74
|
+
rest? · How fresh is it?
|
|
75
|
+
|
|
76
|
+
1. `meta` — the pipeline and what depends on its output.
|
|
77
|
+
2. Prose — why batch or stream; the cost of staleness in user terms.
|
|
78
|
+
3. `dfd` (processes and stores) or `sankey` (when volumes are the story).
|
|
79
|
+
Prose after: the stage that loses or transforms data.
|
|
80
|
+
4. `erd` — the shape at rest.
|
|
81
|
+
5. `steps` — the backfill / replay procedure an operator runs.
|
|
82
|
+
6. `slo` — the freshness targets the team commits to.
|
|
83
|
+
|
|
84
|
+
Rejected: `sequence` (a pipeline has no request/response pairing to draw).
|
|
85
|
+
|
|
86
|
+
Zone patterns compose — they are not block types. A medallion view
|
|
87
|
+
(bronze → silver → gold) is `block` with `layers`: one layer per zone, one
|
|
88
|
+
node per dataset with `tech` for format and retention, edges for the
|
|
89
|
+
promotions. A deployment topology is `block` with `preset: infra` and
|
|
90
|
+
`groups` for the account and network boundaries.
|
|
91
|
+
|
|
92
|
+
## State machine
|
|
93
|
+
|
|
94
|
+
Reader questions: What states exist? · What forces a transition? · What is
|
|
95
|
+
illegal?
|
|
96
|
+
|
|
97
|
+
1. `meta` — the object whose lifecycle this is.
|
|
98
|
+
2. Prose — why these states exist; the invariant the machine protects.
|
|
99
|
+
3. `state` — states and transitions.
|
|
100
|
+
4. `table` — transition × guard × side effect.
|
|
101
|
+
5. `sequence` — one path that exercises the risky transition. Prose after:
|
|
102
|
+
what a caller observes while it runs.
|
|
103
|
+
6. `callout` — the illegal states, and why they must stay illegal.
|
|
104
|
+
|
|
105
|
+
Rejected: `flow` (flows end; lifecycles loop back).
|
|
106
|
+
|
|
107
|
+
## Incident writeup
|
|
108
|
+
|
|
109
|
+
Reader questions: What happened, when? · Why did it break? · What did it
|
|
110
|
+
cost? · What prevents recurrence?
|
|
111
|
+
|
|
112
|
+
1. `meta` — incident id, date, severity.
|
|
113
|
+
2. `timeline` — detection to resolution. Prose after: where the response was
|
|
114
|
+
slow, and why.
|
|
115
|
+
3. `sequence` or `flow` — the failure mechanism, not the happy path.
|
|
116
|
+
4. `stats` — the impact in numbers.
|
|
117
|
+
5. `steps` — remediation, each step with an owner.
|
|
118
|
+
6. `takeaways` — what the organization keeps from the incident.
|
|
119
|
+
|
|
120
|
+
Rejected: `scqa` (a postmortem argues with evidence, not narrative).
|
|
121
|
+
|
|
122
|
+
## ADR
|
|
123
|
+
|
|
124
|
+
Reader questions: What forced a decision? · What were the options? · What did
|
|
125
|
+
we accept by choosing?
|
|
126
|
+
|
|
127
|
+
1. `meta` — the decision's id and title.
|
|
128
|
+
2. Prose (Context) — the forcing fact, with a number in it.
|
|
129
|
+
3. `options` — candidates against the criteria, verdict per card.
|
|
130
|
+
4. `callout` (title "Decision") — the decision in one sentence.
|
|
131
|
+
5. `proscons` — the consequences of the winner, both directions. Prose after:
|
|
132
|
+
the tradeoff the team explicitly accepts.
|
|
133
|
+
6. `statustable` — the follow-up work the decision creates.
|
|
134
|
+
|
|
135
|
+
Rejected: `harvey` (only when criteria resist numbers) · `scorecard`
|
|
136
|
+
(weights imply a precision most ADRs do not have).
|
|
137
|
+
|
|
138
|
+
## API reference
|
|
139
|
+
|
|
140
|
+
Reader questions: What can I call? · What do errors look like? · How do calls
|
|
141
|
+
compose?
|
|
142
|
+
|
|
143
|
+
1. `meta` — the API and its version.
|
|
144
|
+
2. Prose — auth model, versioning, base URL: what endpoint cards cannot
|
|
145
|
+
carry.
|
|
146
|
+
3. `endpoint` × N — one card per operation, examples included.
|
|
147
|
+
4. `sequence` — a multi-call workflow. Prose after: the ordering rule the
|
|
148
|
+
workflow depends on.
|
|
149
|
+
5. `table` — the error codes and what the client should do about each.
|
|
150
|
+
6. `glossary` — the domain terms the paths use.
|
|
151
|
+
|
|
152
|
+
Rejected: `packet` (binary protocols only) · standalone `code` (snippets
|
|
153
|
+
live inside the endpoint cards).
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# STE discipline — style rules for Chiltepin text
|
|
2
|
+
|
|
3
|
+
Aerospace maintenance manuals follow rules like these so that a technician who
|
|
4
|
+
reads English as a second language cannot read a step in two ways. Our failure
|
|
5
|
+
mode is the same: text that looks fluent but means several things. These rules
|
|
6
|
+
adapt ASD-STE100 Simplified Technical English to software documentation. They
|
|
7
|
+
trade style for one property: each sentence has exactly one reading.
|
|
8
|
+
|
|
9
|
+
## Vocabulary and terms
|
|
10
|
+
|
|
11
|
+
- One word, one meaning. If `build` names a command, do not also use it for
|
|
12
|
+
the compiled output.
|
|
13
|
+
- One concept, one word. If the doc says `endpoint`, it never says `route`,
|
|
14
|
+
`path`, or `handler` for the same thing.
|
|
15
|
+
- Project terms live in a `glossary` block. That block is the approved term
|
|
16
|
+
list for the doc. For every term outside it, use ordinary English.
|
|
17
|
+
- Prefer the short common word: use, not utilize; before, not prior to; end,
|
|
18
|
+
not terminate; about, not approximately.
|
|
19
|
+
|
|
20
|
+
## Sentences
|
|
21
|
+
|
|
22
|
+
- Length limits: instructions, 20 words at most; descriptive sentences, 25.
|
|
23
|
+
- Write one instruction per sentence.
|
|
24
|
+
- Instructions are always active voice: "Run `chiltepin check`", never "`chiltepin check`
|
|
25
|
+
should be run". Passive voice is allowed only in descriptive text, and only
|
|
26
|
+
when the actor is truly unknown or irrelevant.
|
|
27
|
+
- Use simple tenses only: past, present, future. No perfect or continuous
|
|
28
|
+
forms.
|
|
29
|
+
- Put the main action first and the condition after it: "Rerun the build if
|
|
30
|
+
the check fails."
|
|
31
|
+
- Keep articles and relative pronouns: "Run the check that validates the doc",
|
|
32
|
+
not "Run check validates doc". When you drop these small words, the sentence
|
|
33
|
+
becomes ambiguous.
|
|
34
|
+
- Keep noun clusters to 3 words at most. Write "the handler that refreshes
|
|
35
|
+
authentication tokens", not "authentication token refresh handler".
|
|
36
|
+
- Do not use an -ing word as a noun or modifier where a verb or clause works.
|
|
37
|
+
Write "when the parser fails", not "on parsing failure".
|
|
38
|
+
|
|
39
|
+
## Paragraphs
|
|
40
|
+
|
|
41
|
+
- Descriptive paragraphs hold 6 sentences at most; procedural paragraphs, 3.
|
|
42
|
+
- Give each paragraph one topic. Announce the topic in the first sentence.
|
|
43
|
+
- Put warnings and prerequisites before the step they apply to, never after.
|
|
44
|
+
|
|
45
|
+
## Where each level applies
|
|
46
|
+
|
|
47
|
+
**Full STE** — procedural and machine-adjacent text: `steps` blocks, CLI help,
|
|
48
|
+
`chiltepin check` diagnostics, error messages, MCP tool descriptions, and the skill's
|
|
49
|
+
own instructions. A reader parses this text under pressure, and the reader is
|
|
50
|
+
sometimes another model. Every rule above applies.
|
|
51
|
+
|
|
52
|
+
**STE-lite** — `prose`, `callout`, and `pullquote` content, and plain Markdown
|
|
53
|
+
paragraphs. Every rule applies except the restricted vocabulary. Prose carries
|
|
54
|
+
tradeoffs and consequences; a controlled word list flattens that. Keep the
|
|
55
|
+
sentence limits, active voice, and simple tenses, and keep one word per
|
|
56
|
+
concept.
|
|
57
|
+
|
|
58
|
+
**STE-lite, completeness first** — block text fields (`description`, `lede`,
|
|
59
|
+
`body`, `note`, `subtitle`, `summary`). The form rules apply, but never delete
|
|
60
|
+
a fact to satisfy a length rule. Split a long sentence into two sentences.
|
|
61
|
+
Keep every component, value, and condition the field states.
|
|
62
|
+
|
|
63
|
+
**Not applied** — marketing copy, changelog voice, code comments. Diagram data
|
|
64
|
+
(node names, messages, edge labels, states, values) is never edited for style:
|
|
65
|
+
the diagram is the data, and it must stay complete.
|
|
66
|
+
|
|
67
|
+
## Worked pairs
|
|
68
|
+
|
|
69
|
+
**Pair 1 — a restated diagram (docs/showcase.md:512).**
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Before: A controller calls OrderService, which loads via an OrderRepository,
|
|
73
|
+
charges through a PaymentGateway interface (Stripe/Adyen adapters), and
|
|
74
|
+
egresses to Postgres, the event bus, and external gateways.
|
|
75
|
+
|
|
76
|
+
After: Payment providers sit behind one interface, so a Stripe outage is a
|
|
77
|
+
config change, not a code change.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The before repeats what the diagram already shows. The after states the
|
|
81
|
+
consequence that the diagram cannot show.
|
|
82
|
+
|
|
83
|
+
**Pair 2 — a lede with three jobs (resources/orders-api.md:29).**
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
Before: Time runs downward. Solid arrows are synchronous requests; dashed are
|
|
87
|
+
responses. The order row exists as PENDING only inside the transaction — it is
|
|
88
|
+
CONFIRMED before commit, or rolled back to CANCELLED on decline.
|
|
89
|
+
|
|
90
|
+
After: An order is never visible as PENDING outside the transaction: it
|
|
91
|
+
commits as CONFIRMED or rolls back to CANCELLED. Clients can treat every read
|
|
92
|
+
as final.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
The before teaches notation, describes arrows, and buries the invariant. The
|
|
96
|
+
after does one job: the guarantee, and what it lets clients do.
|
|
97
|
+
|
|
98
|
+
**Pair 3 — the wrapper opener (docs/showcase.md:9).**
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Before: The blocks below are rendered from typed YAML fences. Edit the source
|
|
102
|
+
.md file, rerun `chiltepin html`, and the HTML updates accordingly.
|
|
103
|
+
|
|
104
|
+
After: Edit a YAML block to change its diagram. Then run `chiltepin html`. The
|
|
105
|
+
.md file is the only source; there is no rendered state to fix by hand.
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The before is passive, restates the page, and stacks two instructions into one
|
|
109
|
+
sentence. The after gives one instruction per sentence, plus the fact that
|
|
110
|
+
makes the edit safe.
|
|
111
|
+
|
|
112
|
+
## Constraints on how we use STE
|
|
113
|
+
|
|
114
|
+
- ASD-STE100 is free to obtain but not free to redistribute. Never copy the
|
|
115
|
+
specification text or its ~900-word approved dictionary into this repo. We
|
|
116
|
+
apply the rules and keep our own term list.
|
|
117
|
+
- Never claim Chiltepin output "is STE" or "is STE-compliant". Write
|
|
118
|
+
"STE-informed" or "follows STE writing discipline". Certified compliance
|
|
119
|
+
requires the real dictionary, and we do not ship it.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Designing systems — the design method & the architecture blocks
|
|
2
|
+
|
|
3
|
+
Part of the **chiltepin** skill (the hub is `SKILL.md`, one folder up). Read
|
|
4
|
+
this for any architecture or design ask.
|
|
5
|
+
|
|
6
|
+
## Designing a system — reason it, don't template it
|
|
7
|
+
|
|
8
|
+
"Design an X" asks (a notification system, a rate limiter, "how would you build Y
|
|
9
|
+
at scale") are where templating shows worst. Every real system's document
|
|
10
|
+
is shaped by *its* bottleneck. Do the design reasoning; each step emits the block
|
|
11
|
+
that carries it:
|
|
12
|
+
|
|
13
|
+
1. **Requirements — ask, then pin them down.** Functional (what it does) and
|
|
14
|
+
non-functional (scale, latency, consistency, durability). If the user gave no
|
|
15
|
+
scale or constraints, **ask back** (move 1 of the method in `SKILL.md`; checklists in `intake.md`). Emit `drivers` — each driver a
|
|
16
|
+
real requirement with its consequence, never a platitude.
|
|
17
|
+
2. **Envelope math.** Users × actions × fan-out → QPS, storage/day, peak factor.
|
|
18
|
+
Emit `stats` with the numbers that justify the architecture — skip when scale
|
|
19
|
+
genuinely isn't the story.
|
|
20
|
+
3. **Contract.** The API surface (`endpoint` per route that matters) and the data
|
|
21
|
+
model (`erd`). These fix the names every later block reuses.
|
|
22
|
+
4. **High level, shaped by the dominant motion.** Request/reply system → `c4`;
|
|
23
|
+
things flowing through stages → `block` (`preset: event`) or `dfd`;
|
|
24
|
+
deployment/regions/zones → `block` (`preset: infra`); a k8s estate →
|
|
25
|
+
`cluster`. One overview diagram of the whole system, using the real names
|
|
26
|
+
from step 3.
|
|
27
|
+
5. **Deep-dive the bottleneck — this is where documents differ.** Work out what
|
|
28
|
+
actually breaks at the stated scale, and design *that* section:
|
|
29
|
+
- hot reads → caching + invalidation (a `sequence` of the miss path)
|
|
30
|
+
- write spikes → queue + backpressure (a `flow` with the shed path)
|
|
31
|
+
- fan-out → push vs pull (`options`, then the chosen `sequence`)
|
|
32
|
+
- cross-service consistency → outbox/saga (a `state` of the saga)
|
|
33
|
+
- geo-latency → replication + CDN (a `preset: infra` `block` per region)
|
|
34
|
+
|
|
35
|
+
One or two deep dives, chosen by the numbers from step 2 — never a fixed list.
|
|
36
|
+
6. **Trade-offs on the record.** The genuine alternatives as `options` (with
|
|
37
|
+
`tone: chosen` on the winner), or `proscons` when only one option's tension
|
|
38
|
+
matters. A design doc with no rejected alternative wasn't a decision.
|
|
39
|
+
7. **Failure & operations.** What breaks, the blast radius, how it degrades: a
|
|
40
|
+
`table` of failure modes → responses, `kind: error`/`forbidden` edges on the
|
|
41
|
+
diagrams, a `flow` of the degradation path.
|
|
42
|
+
8. **Plan.** `timeline` for phasing, `statustable` for the open questions you
|
|
43
|
+
asked in step 1 but didn't get answered.
|
|
44
|
+
|
|
45
|
+
**Patterns are ingredients, not the meal.** When a named pattern is load-bearing
|
|
46
|
+
(pub-sub, saga, circuit breaker, CQRS, …), write it as a `pattern` card plus
|
|
47
|
+
one structure diagram that fits it (`block` for system patterns, `felogic` or
|
|
48
|
+
`uml` for code patterns, `flow`/`state`/`sequence` for agent patterns). Then
|
|
49
|
+
**name every node in the user's domain**: a card whose participants are still
|
|
50
|
+
"ServiceA" was pasted, not designed. Comparing patterns side by side → a
|
|
51
|
+
`gallery` with a nested `pattern`/diagram per cell.
|
|
52
|
+
|
|
53
|
+
The outline that falls out of steps 1-8 differs per system. A rate limiter's doc
|
|
54
|
+
is mostly steps 4-6 with algorithmic depth (`state`, `code`). A social feed's is
|
|
55
|
+
dominated by step 5 fan-out math, a payments integration by step 7 failure
|
|
56
|
+
semantics. **If two of your design docs share the same section list, you skipped
|
|
57
|
+
step 5.**
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
## Architecture and topology (which one when?)
|
|
61
|
+
|
|
62
|
+
| If you want to show… | Use | Notes |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| Who uses the system + which external systems it depends on | `c4` (level: context) | One node per actor / system |
|
|
65
|
+
| Containers inside a system, with optional boundary box | `c4` (level: container) | Use `family` to colour-code (client / service / data / store) |
|
|
66
|
+
| Components inside one container | `c4` (level: component) | Same shape, finer granularity |
|
|
67
|
+
| Generic boxes-and-arrows architecture | `block` | Grid layout; add `groups` for dashed zones; add `layers` to switch to horizontal-band layout |
|
|
68
|
+
| Cloud deployment (CDN, gateway, compute, DB, …) | `block` (`preset: infra`) | Same engine; the preset frames it for cloud topology |
|
|
69
|
+
| Pub/sub event topology (producers → topics → consumers) | `block` (`preset: event`) | Same engine; framed for choreography |
|
|
70
|
+
| Bounded-context map for DDD | `block` (`preset: ddd`) | Same engine; framed for context maps |
|
|
71
|
+
| Security zones with trust boundaries | `block` (`preset: network`) | Same engine; supports `kind: forbidden` edges (red) |
|
|
72
|
+
| Kubernetes-style namespaces with services inside | `cluster` | Has its own nested-box engine; supports `replicas` count |
|
|
73
|
+
|
|
74
|
+
> Every `block` preset shares **one renderer** — presets differ only by the
|
|
75
|
+
> colored tag pill above the diagram (ARCH / INFRA / EVENT / DDD / ZONES) and
|
|
76
|
+
> the section eyebrow. Pick the preset that best signals intent to a reader;
|
|
77
|
+
> the YAML grammar is identical. (The old type names `infra` / `event` / `ddd`
|
|
78
|
+
> / `network` still work as permanent aliases.)
|
|
79
|
+
|
|
80
|
+
**Quick mode — no coordinates.** Every architecture diagram can be written as
|
|
81
|
+
just nodes + edges. Omit `col`/`row` on **all** nodes and the renderer computes a
|
|
82
|
+
clean left-to-right layered layout from the edges. This is the default way to
|
|
83
|
+
sketch a system fast.
|
|
84
|
+
|
|
85
|
+
Add explicit coordinates only when you want a deliberate
|
|
86
|
+
shape — and always when you use `groups`. Zones are anchored to grid cells, so
|
|
87
|
+
they need placed nodes. If *any* node has coordinates but others don't, the
|
|
88
|
+
auto-layout replaces all of them — place all or none.
|
|
89
|
+
|
|
90
|
+
**Edge labels — dense diagrams renumber themselves.** On every edge-bearing
|
|
91
|
+
diagram (`block` — any preset, `flow`, `dfd`, `graph`,
|
|
92
|
+
`swimlane`, `uml`, `cluster`, `felogic`), up to three labelled edges
|
|
93
|
+
render as text pills riding the arrows. At **four or more labelled edges** the
|
|
94
|
+
renderer switches to circled step numerals and moves the label
|
|
95
|
+
text to a numbered legend under the diagram. (`state` is the one exception —
|
|
96
|
+
its numerals point at the transition table's rows instead of a second legend.)
|
|
97
|
+
You don't opt in or lay anything out. Just keep edge labels short (a verb
|
|
98
|
+
phrase, a couple of words) so they read well as a pill or a legend entry.
|
|
99
|
+
|
|
100
|
+
**Node kinds** (block family; free strings — known ones get a colour + glyph):
|
|
101
|
+
`client` · `service`/`microservice`/`compute`/`container` · `worker`/`etl` ·
|
|
102
|
+
`db`/`store`/`database` · `bucket`/`blob` · `queue`/`mq`/`broker` · `stream` ·
|
|
103
|
+
`cache` · `gateway`/`lb`/`proxy` · `function`/`lambda` · `cdn` · `dns` ·
|
|
104
|
+
`waf`/`firewall`/`shield` · `auth`/`idp`/`iam`/`oauth`/`sso` ·
|
|
105
|
+
`secrets`/`vault`/`kms` · `monitor`/`metrics`/`logs`/`tracing` ·
|
|
106
|
+
`scheduler`/`cron`/`job` · `warehouse`/`lake` · `analytics`/`bi` ·
|
|
107
|
+
`search`/`index` · `ml`/`model`/`llm`/`agent` · `vm`/`server`/`host` ·
|
|
108
|
+
`user`/`person`/`browser`/`mobile` · `users`/`crowd` · `device`/`iot` ·
|
|
109
|
+
`notification`/`webhook` · `email`/`sms` · `ci`/`cicd`/`pipeline` · `git`/`repo`
|
|
110
|
+
· `registry` · `config` · `shard`/`sharded` · `replica`/`replicaset` ·
|
|
111
|
+
`region`/`geo`/`globe` · `producer`/`topic`/`consumer` · `context` · `external`.
|
|
112
|
+
**Vendor names work too**: `postgres`/`mysql`/`mongo`/`dynamo` → db, `s3` →
|
|
113
|
+
bucket, `sqs`/`rabbitmq` → queue, `kafka`/`kinesis` → stream,
|
|
114
|
+
`redis`/`memcached` → cache, `elasticsearch`/`opensearch` → search. Pick the
|
|
115
|
+
closest kind — an unknown kind renders as a neutral box.
|
|
116
|
+
|
|
117
|
+
**Kinds also pick the shape** (the canonical system-design silhouettes — you get
|
|
118
|
+
the right one automatically by choosing the right kind):
|
|
119
|
+
|
|
120
|
+
| Shape | Kinds |
|
|
121
|
+
|---|---|
|
|
122
|
+
| cylinder | `db` `database` `store` `postgres` `mysql` `mongo` `dynamo` |
|
|
123
|
+
| tiered cylinder | `warehouse` `lake` |
|
|
124
|
+
| pail (bucket) | `bucket` `blob` `object` `s3` |
|
|
125
|
+
| **sharded trio** (3 small cylinders) | `shard` `shards` `sharded` |
|
|
126
|
+
| **replica set** (stacked cylinders) | `replica` `replicas` `replicaset` |
|
|
127
|
+
| horizontal cylinder (pipe) | `queue` `topic` `stream` `mq` `broker` `sqs` `rabbitmq` `kafka` `kinesis` |
|
|
128
|
+
| cloud | `cdn` `external` |
|
|
129
|
+
| hexagon | `gateway` `proxy` |
|
|
130
|
+
| octagon | `lb` |
|
|
131
|
+
| instance stack (receding cards) | `cache` `redis` `memcached` `worker` `etl` |
|
|
132
|
+
| server rack (stacked slabs) | `vm` `server` `host` |
|
|
133
|
+
| shield | `waf` `firewall` `shield` |
|
|
134
|
+
| actor figure (boxless) | `user` `person` `actor` |
|
|
135
|
+
| crowd (overlapping figures) | `users` `crowd` |
|
|
136
|
+
| browser window | `browser` `web` |
|
|
137
|
+
| phone frame | `mobile` |
|
|
138
|
+
| circle with ƒ | `function` `lambda` |
|
|
139
|
+
| calendar with clock badge | `scheduler` `cron` `job` |
|
|
140
|
+
| padlock | `secrets` `vault` `kms` |
|
|
141
|
+
| globe (boxless) | `region` `geo` `globe` |
|
|
142
|
+
| clean rounded card + glyph | everything else |
|
|
143
|
+
|
|
144
|
+
The same silhouettes apply inside `felogic` (db/store → cylinder,
|
|
145
|
+
queue/bus/broker → pipe, cache → stack, external/backend/api → cloud), in `c4`
|
|
146
|
+
(`kind: store` → cylinder), and in `cluster` (db services → cylinder). A
|
|
147
|
+
database looks like a database in every diagram.
|
|
148
|
+
|
|
149
|
+
**C4 extras.** Edges take `tech:` — rendered as `label [tech]`, the C4
|
|
150
|
+
convention for the protocol. `boundaries[]` draws several named dashed boxes,
|
|
151
|
+
each fitted around an explicit `nodes: [ids]` list (optional `color`) — so one
|
|
152
|
+
diagram shows your platform and a partner's estate side by side. The single
|
|
153
|
+
auto-fit `boundary:` still works for one system.
|
|
154
|
+
|
|
155
|
+
**Mixing architecture views — one overview + one zoom.** Show the whole system
|
|
156
|
+
once (`c4` context, or a `block` landscape), then zoom into the one or
|
|
157
|
+
two places the doc is actually about. Zoom with `felogic` (or its `variant:
|
|
158
|
+
be`) for a module's internals, a `preset: infra` `block` or `cluster` for
|
|
159
|
+
deployment, and a `sequence` for the runtime of one path. Never redraw the same boxes in a
|
|
160
|
+
second engine — pick one block per level of zoom and stitch them with prose
|
|
161
|
+
("inside the `api` container: …").
|