with one click
with one click
| name | local-tech-design |
| description | Tech Design Genius |
**…** so the text is bold even in renderers that don't auto-bold the header row.**…** gives bold + gray-bg with no extra markup.| **Field** | **Type** | **Notes** | **Details** | — applies to every table in the doc, not just field tables.Brevity is the rule everywhere. Every section, every bullet, every table cell, every code-block name, every diagram label. The whole tech doc should be skimmable in under five minutes and still convey every key point.
region to GetFooRequest" beats "extend the request schema with the geographic context needed downstream".Code change summary doesn't recap the diff.Every diff in the doc — Go/Python/etc. code, Thrift/Protobuf IDL, SQL DDL, YAML config, anything else — uses the same parent-context pattern. The point: reviewers should grok WHERE in the parent block the change lives, which conditions/fields surround it, and what runs after, without us pasting the entire block. This rule is referenced from §5 and §6 (and anywhere else a diff appears) — do NOT redefine it inline; just follow it. Pattern, in order:
func DoThing(ctx context.Context, …) error { for a function, struct GetFooRequest { for an IDL struct, service FooService { for an IDL service, CREATE TABLE foo ( for SQL DDL, etc.... on its own line to elide an uninteresting middle stretch.- / + lines.... to elide whatever's left in the parent block.
Use a fenced diff block. Identifier names appear naturally in the diff; no extra prose call-out needed.
Every diff block MUST be wrapped in a named, collapsible <details> element in source. Source format:<details>
<summary><strong><code-block name per Sync rule #9 conventions></strong></summary>
```diff
<diff content>
```
</details>
This makes the block render as a collapsed disclosure widget on GitHub / GitLab natively, and on Lark / Confluence the converter maps the wrapper to the platform's native collapsible code primitive (collapsed by default + named title) — see Sync-to-remote rule #9 for the per-platform conversion. Never emit a bare diff block without the wrapper.
Exception — fully NEW parent block: when the parent function/struct/service/table itself is new (no prior version exists), show the entire definition with + on every line, no ... elisions — reviewers need the full thing because there is no "around it" to scan. This applies to a brand-new RPC method (full IDL method + request + response structs), a new struct, a new SQL table, a new endpoint, etc.
Code-change example (existing function, placeholders only):
```diff
func <ParentFunc>(ctx context.Context, input *<InputType>) (*<OutputType>, error) {
if input == nil {
return nil, <ErrNilSentinel>
}
...
result, err := <fetchFromA>(ctx, input.ID)
if err != nil {
return nil, err
}
- if <existing condition> {
- result, err = <fetchFromB>(ctx, input.ID)
+ if <existing condition> || <new condition> {
+ result, err = <fetchFromB>(ctx, input.ID)
+ <writeToA>(ctx, input.ID, result, <ttl>)
}
if err != nil {
return nil, err
}
...
}
```
IDL-diff example (existing struct, adding one field — Thrift placeholder):
```diff
struct <RequestStruct> {
1: required i64 user_id
2: optional string region
...
5: optional i32 page_size
+ 6: optional bool include_deleted
7: optional string cursor
...
}
```
IDL-diff example (NEW method — show everything, no elision):
```diff
+service <ServiceName> {
+ <ResponseStruct> <NewMethod>(1: <RequestStruct> req)
+}
+
+struct <RequestStruct> {
+ 1: required i64 user_id
+ 2: optional string region
+}
+
+struct <ResponseStruct> {
+ 1: required i32 status
+ 2: optional string message
+}
```
Define the cell shape ONCE here; rules elsewhere (§3 Detail, §3 Decisions, anything else that needs nested content in a table cell) reference this format and add only their own content constraints. Do NOT redefine the encoding inline. Source encoding — kept compact so the cell stays a valid Markdown table cell while still being parsable into a nested list:
**<header text>**. No leading bullet character. Header text is short.• (bullet + space) followed by the bullet text.<br> separates lines within a Level-1 item (between the header and its first sub-bullet, between consecutive sub-bullets).<br><br> separates Level-1 items.<br> IS permitted in any cell that opts into this format (overrides the "single-line cells only" rule for those specific cells).
Generic shape:
**<L1 header A>**<br>• <sub-bullet A.1><br>• <sub-bullet A.2><br><br>**<L1 header B>**<br>• <sub-bullet B.1>
Remote rendering: the Sync-to-remote rule converts cells in this format to platform-native nested lists (Lark bullet blocks at indent depth 1/2, Confluence nested <ul><li>, Google Docs createParagraphBullets with nestingLevel: 1, GFM <ul><li> HTML for git markdown). Never let <br> or • survive as literal text on the rendered page.
When a rule references this format, it specifies only what's specific to that use:**Option <N> — <name>**).local_workspaces/ container folder and any subfolder containing a workspace.yml: every workspace created by mkws lives at <root>/local_workspaces/<name>/ and its contents are duplicates of sibling repos already in the root. Skip the entire local_workspaces/ tree (and defensively any other workspace.yml-bearing folder); only consider the original sibling repos as candidates for the mapping.The tech doc MUST follow this exact section structure. Do not reorder, do not skip; if a section doesn't apply, leave it with a one-line "N/A — " rather than removing it.
Heading levels in the OUTPUT tech doc — do NOT start the file with a top-level # <Tech Doc Title> heading. The doc starts directly at # 1. Overview & Background.
Heading hierarchy is strict and contiguous: H1 > H2 > H3 > H4 > H5. Never jump (no # Section directly to ### Sub-sub-block). Per-section levels:
| Section | H1 | H2 | H3 | H4 | H5 |
|---|---|---|---|---|---|
| §1, §2, §7, §8 | # N. <name> | — | — | — | — |
| §3 Design Decisions | # 3. Design Decisions | none by default — entire section is ONE table; H2 sub-sections (## 3.X <name>) added ONLY when user explicitly asks for a deeper writeup | — | — | — |
| §4 Solution Overview | # 4. Preferred Solution Overview | ## 4.1 Architecture flowchart, ## 4.2 Cross-service sequence diagrams | ### <diagram name> (under §4.2 — required when there are 2+ sequence diagrams; omit the H3 when there's exactly 1) | — | — |
| §5 External | # 5. External Technical Design | ## <method/api_name> | ### Request, ### Response, ### Logic change, ### Code change | — | — |
| §6 Internal | # 6. Internal Technical Design | ## 6.X Service: <Name> | ### API changes, ### Infra changes, ### Impact + mitigation (omitted by default — keep ONLY if there's a genuinely critical cross-cutting risk; cap 3 points) | #### <method/api_name> (under API changes) or #### Redis library change etc. (under Infra changes) | ##### Request, ##### Response, ##### Logic change, ##### Code change |
The examples below use ### N. for §1..§8 purely because they're embedded in this SKILL.md (which has its own H1/H2 above). In the tech doc you generate, those become # N., every #### X.Y becomes ## X.Y, and so on per the table above.
Placeholder block — the user fills in URLs later. Pre-populate with empty bullets:
- Tracking ticket:
- PRD / requirement doc:
- Related MRs:
- Monitoring / dashboards:
- Other:
ONE single table for the entire §3 — by default, no sub-headings, no per-decision prose, no separate comparison tables. Every meaningful design choice lives as a row in the same table so reviewers see the whole set at a glance. High-impact only — cap at 3–4 rows total. Each row answers ONE concrete question that came up while designing AND would meaningfully change the architecture if picked differently (caching strategy, data-sync model, schema shape that crosses services, rollout strategy with risk, error semantics that propagate, etc.). Drop trivial / obvious / upstream-fixed choices entirely; their resolution shows up naturally in the §6 Code change diff. What to OMIT as a row:
N/A — all design choices fixed by <link in §2>. If you have more than 4 rows, drop the weakest until only heavyweights remain.
The table — exactly 4 columns, in this exact order:
| # | Name | Detail | Decisions |
| ------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 3.1 | | Summary3.<N>, contiguous starting at 3.1.?, no "How should we…", no "Should we…"). Scannable.**Summary**, then **Target**.?, no "Should we…"). Summary bullets state the constraint / trigger that forces this decision; Target bullets state the concrete goal we're aiming for.Option 1. Alternatives become Option 2, Option 3 in any order. The **(Preferred)** suffix still appears on Option 1 for explicit visual confirmation, but its position alone signals the pick. Reviewers should never have to scan past Option 1 to find what was chosen.**Option <N> — <short name>**, numbered contiguously from 1.Criterion × Option comparison table. Add a (see §3.2 below) pointer in the table's row when this happens.The "wide-angle lens" section: every reader should be able to grok the new architecture and its cross-service flows from §4 alone, without scrolling into the per-service deep-dive in §6. §4 has TWO subsections, in this exact order:
flowchart showing services + primary data flow.classDef/linkStyle snippet.sequenceDiagram block per non-trivial cross-service interaction (≥2 hops, async edges, retries). Trivial single-RPC calls don't need one.### <short diagram name>. The name is a short noun phrase describing what the flow is (e.g. ### Order placement, ### Refund cancellation, ### Cache miss read path) — keep it scannable, not a sentence. When there is exactly one sequence diagram, omit the H3 entirely (the §4.2 heading covers it).sequenceDiagram (e.g. as a Note over Participant: ... block or in the participant names themselves).(NEW) marker + green styling rule as the §4.1 flowchart — keeps the visual signal consistent across diagrams.METHOD /path/with/{params} (e.g. POST /v1/<resource>, GET /v1/<resource>/{id}).<Service>.<Method> exactly as registered in the IDL (e.g. <ServiceA>.<MethodX>).SELECT FROM <table>, UPDATE <table> SET <field>, INSERT INTO <table>). For complex queries, name the named query / stored proc.GET <key>:{id}, SET <key>:{id} EX <ttl>).PRODUCE <topic> / CONSUME <topic> (e.g. PRODUCE <cluster>.<topic>).<S3-style> PutObject bucket=…, gRPC stream <StreamName>, etc.).call, request, read, write, query, update, notify, event, process on their own. If you can't name the operation, the arrow is ambiguous — fix the diagram before keeping it.N/A — internal-only change and move on.## <method/api_name> (H2) — one block per external method that changes.### Request### Response### Logic change### Code change### Request and ### Response — TWO artefacts in this exact order:
Field | Type | Notes | Details 4-column field table (format below).+ on every line, no ... elisions.-/+ lines + ... for elided middles).| **Field** | **Type** | **Notes** | **Details** |
| --------- | -------- | --------- | --------------------------------------- |
| field_a | int64 | New | <one-line purpose / constraint> |
| field_b | int64 | Updated | was string; widened to int64 |
| field_c | int64 | Exist | included for context — no change |
| field_d | int64 | Removed | replaced by field_e in v2 clients |
<br>. Write field_a, never `field_a`. Same in prose: refer to fields plainly. Backticks belong only on actual code snippets, never on field names.New, Updated, Exist, Removed. Nothing else in this column. Reviewers scan this column to see the shape of the diff at a glance.Updated, the constraint or purpose for New, the reason an Exist row is in the table at all (context, backcompat, still required by some client), the deprecation path for Removed. Keep it concise — one short phrase per row, no sentences, no nested bullets, no <br>. If a row has no real reason to exist beyond completeness, drop the row.Two-level structure: Service → then API-method (or Infra-action). Use the codebase mapping from the <tech_doc_name>_mapping.md file as the canonical service list. For each service that changes:
For EACH API method that changes, one block, in this exact order:
Each per-method block (#### <method> H4 in the tech doc) has these fixed-label sub-headings at H5, in this exact order:
##### Request##### Response##### Logic change##### Code changeIf the same API is already documented in §5 (External Technical Design), omit Request and Response entirely — no heading, no field table, no IDL diff block, no pointer, no "see §5" line. The block then has only Logic change + Code change headings. Don't duplicate the schema or IDL across sections.
The content under each heading:
Field | Type | Notes | Details 4-column table (only rows worth listing).+ on every line, no elisions; existing method → diff with parent-context pattern.Only use this section when the change touches infrastructure (Redis client, Kafka consumer, DB driver, message broker, cache layer, etc.). Each block is named by the infra action, never by source file or function:
Examples of infra-action block names (H4 in the tech doc):
#### Redis library change#### Kafka consumer change#### DB schema migrationEach infra-action block has these fixed-label sub-headings at H5:
##### Logic change — high-level only, same rule as API changes.##### Code change — diff per the universal Diff format rule (covers code AND schema/DDL/config diffs).Omit this heading entirely by default. Only include it when the service introduces a genuinely critical, cross-cutting risk that reviewers must be warned about up front (e.g. breaking change to an upstream contract, data migration with rollback constraints, latency budget eaten by a new sync RPC). If nothing meets that bar — no heading, no empty placeholder, no "N/A". Keep the noise floor low. When kept, the section is a tight nested list — at most 3 critical points. Format:
Mitigation: , stating concretely how the risk is handled (feature flag, rollout step, fallback path, monitoring alert, etc.). One line.- <Problem 1 in one line>
- Mitigation: <one-line concrete handling>
- <Problem 2 in one line>
- Mitigation: <one-line concrete handling>
— Do NOT put sequence diagrams here; those live in §4.2 so they're surfaced before the deep-dive.
A small Markdown table — exactly 4 columns in this order:
| Microservice / task | Owner | Effort (d) | Notes |
|---|---|---|---|
| <owner / TBD> | |||
| <owner / TBD> | blocked on |
service-a) or short task verb-phrase (e.g. migrate redis client, backfill region column). NO description of what the work does. If the reader needs to know what's in the change, they read §6.TBD if unassigned.0.5, 1, 1.5, …).blocked on <X>, needs DBA review, depends on §3.2 pick). Use the Nested-list table cell format ONLY when there are 2+ structured categories worth listing (e.g. multiple dependencies + multiple risks); cap 3 Level-1 items, 1–3 sub-bullets each. If you can't justify the structure, leave it as a single phrase.Production-deploy only. What physically goes to prod — nothing else. NO dev-flow items (no MR-merge gates, no test-green gates, no review-approval gates, no testing-env deploys, no rollback-doc reminders); those belong in the team's normal CI/CD. Per the TLDR rule, every line is verb + name. NO description of what's in the release, why, or what it does — §6 is the source of truth.
Deploy <service-name>. Just that. Order = rollout order if there's a dependency.Update <namespace>/<key> = <new-value> (<env>) or Enable feature flag <flag-name> (<env>, <%>). NO explanation of what the config controls.- [ ] Deploy <service-a>
- [ ] Deploy <service-b>
- [ ] Update config <namespace>/<key> = <new-value> (prod)
- [ ] Enable feature flag <flag-name> (prod, 100%)
Multi-step example:
- [ ] Deploy <service-c>
- [ ] Run schema migration <name>
- [ ] Deploy app to canary (10%)
- [ ] Promote to 100%
If a service or config is already in §6 as a code change but doesn't need a separate prod action, it does NOT belong here. This is the deploy artefact, not a re-listing of the diff.
+--+ / |, arrows with -->, <--, ==> (sync vs async), labels next to arrows. Sequence diagrams as left-to-right swim lanes with time flowing top-to-bottom. The chat client doesn't render mermaid, so source code is harder to scan than ASCII; the ASCII IS the readable overview.mermaid block (flowchart / sequenceDiagram / classDiagram as appropriate). Mermaid-aware viewers render it inline.new class (classDef new fill:#bbf7d0,stroke:#16a34a,color:#16a34a,font-weight:bold) applied to new nodes — this also colors any (NEW) marker inside the node label green; new edges styled with linkStyle <idx> stroke:#16a34a,stroke-width:2px,color:#16a34a (the trailing color: greens the edge-label text including its (NEW) tag). Tag new nodes/edges with a trailing (NEW) marker in BOTH ASCII and mermaid (use parentheses, never [NEW] — [...] is mermaid node syntax and breaks the parser inside edge labels). The (NEW) text must render green wherever it appears. Existing pieces stay default-styled — the contrast is the point.
ASCII style example (chat) — placeholders only:+----------+ <op A> +-------------+
| Service X| -------------> | Service Y |
+----------+ +------+------+
|
<op B>
|
+---------+---------+
v v
+-----+-----+ +-----+-----+
| Store A | | Store B |
| (NEW) | | |
+-----------+ +-----------+
Mermaid equivalent (tech doc):
flowchart LR
ServiceX -->|<op A>| ServiceY
ServiceY -->|<op B-1>| StoreA
ServiceY -->|<op B-2>| StoreB
classDef new fill:#bbf7d0,stroke:#16a34a,color:#16a34a,font-weight:bold
class StoreA new
linkStyle 1 stroke:#16a34a,stroke-width:2px,color:#16a34a
<tech_doc_name>_mapping.md as the canonical microservice list — never guess service boundaries.HARD RULE — sync is ALWAYS user-invoked, NEVER automatic. Do NOT push the tech doc (or any part of it) to a remote URL on your own initiative. This applies even in auto mode and even when the user has previously synced. Every remote write — first upload, every incremental update, every section replacement — requires an explicit, current-turn instruction from the user (e.g. "sync to ", "push the §6 update to Lark", "update the remote doc"). Until that instruction arrives, the local file under tech_doc/ is the only artefact you touch. If you finish a revision round and notice a remote URL was previously provided, do NOT auto-push the new revision — wait for the user to ask. Surface a one-line reminder if useful (e.g. "Local doc updated. Want me to sync the changes to ?"), then stop.
Trigger: user explicitly asks to sync, and a URL is on hand (either provided this turn or previously confirmed for this doc). Detect the platform from the URL host + path and route to the right skill:
| URL pattern | Platform | Skill / tool |
|---|---|---|
feishu.cn, larksuite.com, larkoffice.com — match sub-path /docx/, /sheets/, /wiki/, /file/ | Lark / 飞书 | lark-doc (docx), lark-sheets (sheets), lark-wiki (wiki node), lark-markdown (raw .md in Drive) |
atlassian.net/wiki/, *.atlassian.com/wiki/, self-hosted Confluence | Confluence | WebFetch + Confluence REST API (/rest/api/content/{id}) |
docs.google.com/document/, docs.google.com/spreadsheets/ | Google Docs / Sheets | mcp__claude_ai_Google_Drive__* deferred tools |
github.com/.../blob/.../*.md, gitlab.*/.../blob/.../*.md, any git-hosted markdown file | Remote markdown in git repo | codebase skill or gh CLI for GitHub |
| If the URL doesn't match any pattern above, ask the user which platform it is rather than guessing. | ||
| Upload algorithm: |
<method>, §6.X Service, §6.X.<method>, etc.) as the diff boundaries. For each heading whose body actually changed, replace only that section remotely. Never overwrite the entire doc.H1 > H2 > H3 > ...). The deepest heading whose body differs is the replacement unit — don't replace a parent if only one child changed. Identical sections are skipped.docs +fetch --section <heading> to read the current section, then docs +update with block_replace / str_replace / block_insert_after targeted at that section's blocks. Never use overwrite on the whole doc.PUT /rest/api/content/{id}. Section-level intent, single-write API.documents.batchUpdate with replaceAllText / insertText requests scoped to the changed section's range; for Sheets, target the cell range that holds that section.tech-doc: update §3.2, §6.1.GetFoo), push or open a PR per repo convention.<br>• run-on text. This applies to the §3 Detail and Decisions columns and any other cell that opts into the format. The remote cell must visually show indented sub-items (Level-1 header > Level-2 sub-bullets), not a single paragraph with • characters and line breaks left as literal text.
• line = Level 2; <br> within an item; <br><br> between items). Preserve the bold marker on Level-1 lines as bold formatting on the rendered list item.<br> and • are PARSER MARKERS, not content. Both characters must be consumed entirely during parsing and never appear in the text content of any rendered list item:
<br> is a structural separator (line boundary inside the cell). It must NOT survive into a rendered list item's body and become a hard line break inside that item. A Level-2 sub-bullet renders as ONE continuous line of text, full stop — no internal <br>-induced line breaks splitting one bullet's text into two visual lines.• (bullet + space) is the Level-2 marker. The platform's native bullet glyph replaces it; the literal • character must NOT appear at the start of the rendered item.**…** becomes bold styling on the rendered item; the ** characters must NOT survive as literal text.<br> or any other hard-break marker inside a sub-bullet's text to force a wrap — that breaks the "one bullet = one logical line" invariant and produces fragmented rendered items.<br>, •, or ** characters appear as literal text anywhere in the rendered list, and (c) no list item has been split into multiple list items by a stray <br>. If any of these fail, the conversion is broken — fix the parser/emitter, don't paper over with text-substitution hacks.bullet list blocks inside the table cell — Level-1 items at indent depth 1, Level-2 sub-bullets at indent depth 2. Use docs +update block-level operations targeting the cell. Never let • survive as a literal character on the rendered page.<ul><li>...</li></ul> for Level 1 with a nested <ul><li>...</li></ul> inside each <li> for Level 2. Strip the source • and <br> markers entirely.documents.batchUpdate with createParagraphBullets requests scoped to the cell range; Level-2 sub-bullets get nestingLevel: 1.<ul><li>...</li></ul> HTML inside the cell — GitHub / GitLab honor the HTML and render proper nested lists.# in §3, **Field** and **Type** in §5/§6 field tables, **Owner** and **Effort (d)** in §7, status checkboxes in §8. Pick the smallest width the platform supports that still keeps the longest cell value on one line.Detail and Decisions in §3, Notes / Details in §5/§6 field tables, Notes in §7, the description text in §8 — distribute the remaining row width proportionally to content density. A single Level-2 sub-bullet should fit on ONE rendered line; Level-1 items shouldn't get fragmented.column_width on each table column block during docs +update; Confluence — emit <colgroup><col style="width: …%"></col>…</colgroup> inside the <table>; Google Docs — updateTableColumnProperties with explicit columnWidthPx per column.<details><summary> wrapper as the canonical encoding (per the universal Diff format rule); the converter maps that wrapper to the platform's native collapsible-code primitive.
<details>
<summary><strong>Code change — <ParentFunc> (path/to/file.go)</strong></summary>
```diff
func <ParentFunc>(...) ... {
...
```
</details>
The summary text follows the Code-block name conventions below.Code change — <ParentFunc> (<short file path>) (e.g. Code change — GetFoo (handler/foo.go)).IDL — <StructName> (<idl file>) (e.g. IDL — GetFooRequest (foo.thrift)).IDL — <ServiceName>.<Method> (<idl file>).SQL — <table_name> (<migration file>).Config — <config key> (<file path or namespace>).<details> wrapper:
language: diff and the summary text set as the block's title; mark the block as collapsed by default. Use lark-doc's collapsible code-block / callout-with-code support.<ac:structured-macro ac:name="code"> with <ac:parameter ac:name="title">…name…</ac:parameter>, <ac:parameter ac:name="language">diff</ac:parameter>, and <ac:parameter ac:name="collapse">true</ac:parameter>.<details><summary>…</summary>…</details> wrapper as-is. GitHub / GitLab render it natively as a collapsed disclosure widget. Do NOT strip the wrapper.[HINT] Download the complete skill directory including SKILL.md and all related files