ワンクリックで
dum-dum-non-ts
Use when writing or editing source files in non-TypeScript general-purpose languages.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Use when writing or editing source files in non-TypeScript general-purpose languages.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Selects and vets SaaS vendors, libraries, frameworks, build tools, local executables, and replacement dependencies through hard gates, source audits, validation, and scored comparison. Use when choosing, recommending, evaluating, vetting, replacing, or comparing technologies or vendors for this repo.
Use when investigating an external tool's behavior, bug, quirk, capability gap, or fix difficulty; proactively write the troubleshooting doc the moment you finish diagnosing or working around one, even when the user did not ask; also use when writing or updating a doc/troubleshooting/<topic>.md file. The write-up is a required completion step, not an offer.
Use when writing manual steps a user must execute (clicks, keys) after bridges failed.
Use when writing or reviewing tests in this monorepo using the module-test harness.
Review code according to project standards
Use when editing CSS, writing component styles, or reviewing CSS in this repo.
| name | dum-dum-non-ts |
| description | Use when writing or editing source files in non-TypeScript general-purpose languages. |
Fires when writing or editing source files in non-TypeScript general-purpose programming languages: C, C++, Rust, Go, Python, Java, Kotlin, Swift, Ruby, PHP, Lua, Zig, Nim, Haskell, OCaml, Elixir, Clojure, Scala, F#, or any other.
The skill encodes two rules (simplest possible constructs; comments on every concept-introducing line) and a comment template (What, Why, optional Gotcha) with a TypeScript pseudocode equivalent above every concept-introducing line.
See "Out of scope" at the bottom for file types this skill does not apply to.
The human reader knows only TypeScript. Optimise comments and code shape for them, not for an experienced practitioner of the target language. The compiler does not read the comments; the user does.
Write boring, beginner-level code. Forbidden by default:
do-notationif/else chain handlescond ? a : bPrefer:
plain named functions,
named local variables,
explicit type
annotations where the language allows them,
if/else,
for loops,
early
returns,
one statement per line.
**If two ways exist,
pick the one whose
translation to TS is mechanical.
**
If the task genuinely needs a construct with no clean TS analogue (manual memory management, lifetimes, async runtimes, FFI, channels), stop and ask the user whether to (a) proceed with a verbose comment that admits the analogy is loose, (b) wrap the gnarly bit in a tiny helper and only use the helper from then on, or (c) pick a different language for this piece.
A line is concept-introducing if it is any of:
#include / use / requireSome(...),
None,
Ok(...),
Err(...),
Box::new(...),
Rc::new(...),
Arc::new(...),
Cell::new(...),
RefCell::new(...),
Vec::new(),
String::new(),
Haskell's Just x / Nothing,
Python's Optional[X] annotation,
etc.
These exist precisely because the language lacks null / throw.
Every
appearance is concept-introducing for a TS reader — including bare
one-token tails like Ok(rules) or None..to_string(),
.to_owned(),
.into(),
.from(...),
.clone(),
.as_str(),
.as_bytes(),
.unwrap(),
.unwrap_or(...),
.unwrap_or_else(...),
.unwrap_or_default(),
.expect(...),
.ok(),
.ok_or(...),
.collect(),
.into_iter(),
the ? propagation operator.
(Same idea
in other languages:
Python's dict.get(k, default),
Go's , ok comma-ok
pattern,
Kotlin's ?: Elvis,
Swift's as! / as?.
)&x,
&mut x,
*x,
Rust lifetimes 'a,
C/C++ pointer arithmetic,
Go's &v / *v.
Even
if the line looks like a plain function call,
every & / &mut
argument is concept-introducing because it states ownership intent
("I am only lending this to you").|x| ... /
|&x| ...,
Ruby do |x| ... end,
Haskell \x -> ...,
etc.match / pattern-match expression used to extract from
Option / Result / sum types (match x { Some(v) => ..., None => ... },
match r { Ok(v) => ..., Err(e) => ... }).
Even one-arm if let Some(v) = x counts.;.
Examples:
Ok(rules),
Some(escape_literal(trimmed)),
(line, col),
if cond { a } else { b }.
The reader has to know both that this is
a return AND understand the value being constructed.
Mark it with the
same comment block as any other concept-introducing line.defer,
with,
list comprehensions,
destructors,
ownership moves,
await on a
non-Promise type,
range-indexing like s[1..n],
byte literals b'/',
type-annotated let bindings like let x: Vec<T> = ...,
let _ = ...
discard,
etc.)<<,
::,
&,
*,
?,
!,
<...> template args,
mut,
'a lifetimes,
-> return type arrows in non-TS positions,
etc.Lines that do not need a comment:
closing braces,
blank lines,
plain
arithmetic whose TS equivalent is character-identical (x + 1),
and
re-assignments to an already-commented variable using only TS-native
operators.
**Comment every recurrence.
** Do not drop the comment block on the second,
third,
or tenth appearance of the same pattern (?,
Some(...),
.to_string(),
& arguments,
match r { Ok(_) => ..., Err(_) => ... },
…) unless the user has explicitly said "you can stop commenting X in this
file".
Repetition is the cost;
clarity is the deliverable.
If a file
becomes unreadable from the comment density,
make the file smaller,
do
not thin out the comments.
Every concept-introducing line gets a comment block above it, written in whichever of the language's comment forms fits the line's role. Do not assume a plain line comment:
/// above the item and //! at the top of the file;
the equivalent
in other languages.
Write the block once,
in the doc-comment form.
Never leave
it as a plain comment and bolt a separate one-line summary on top,
and never
keep both a plain block and a doc-comment summary for the same item.// in C / C++ / Rust / Go /
Java / Swift / Kotlin,
# in Python / Ruby / Elixir,
-- in Haskell / Lua /
SQL,
; in Lisp / Clojure.
Where a doc comment on a non-item is an error
(Rust /// on a statement),
this ordinary comment is the only legal choice.The block's fields are the same whichever comment form carries it:
usize → name u32 / u64 / i32 / i64 as
siblings;
String → name &str as the sibling;
Vec<T> → name
&[T] and [T; N];
Box<T> → name Rc<T> and Arc<T>;
i32 →
name u32 / i64.
Just naming the type is not enough;
the dum-dum
reader has no way to know what alternatives even exist.usize and not u64?
" "Why String and not &str?
"
"Why Box<T> and not Rc<T>?
" One sentence each is enough;
silence
is not.In TS you'd write (pseudocode): — always TS,
regardless of which language the surrounding file is in.
The pseudocode
block IS the TypeScript translation;
that's the whole point.```ts block (inside the language's comment syntax) holding
the closest TS translation.
Comments inside the block may further narrate.Comments never describe the next line in the target language's own
jargon ("declares a unique_ptr<T>").
Translate to TS-thinking:
"an owning
reference to a heap-allocated T — when this variable goes out of scope,
the T is freed automatically".
// What: `#include <iostream>` is C++'s "paste this file in here at
// compile time" directive. `<iostream>` is the standard library
// header that defines input/output streams. The `<...>` form
// tells the compiler to look for the file in the standard library
// directories (vs `"..."` which means "in my project").
// Why: We need it so the `std::cout` line below is defined. Without
// this `#include`, the file does not compile.
//
// In TS you'd write (pseudocode):
// ```ts
// // No 1:1 equivalent — TS gives you `console.log` for free.
// ```
#include <iostream>
// What: `int main() { ... }` declares a function named `main` that
// takes no arguments and returns an `int` (a 32-bit signed
// integer). The `{ ... }` is the function body.
// Why: Every C++ program must have exactly one `main`. The OS calls it
// when the program starts; whatever it returns becomes the
// program's exit code.
// Gotcha: `int` is NOT TS's `number`. It is a fixed-width 32-bit signed
// integer (range roughly ±2.1 billion). Overflow is undefined
// behaviour — there is no auto-widening to `bigint`.
//
// In TS you'd write (pseudocode):
// ```ts
// async function main(): Promise<number> {
// // ...body goes here...
// return 0;
// }
// ```
int main() {
// What: `std::cout` is the standard "character output" stream — an
// object that represents the terminal's stdout. `<<` is the
// "stream insertion" operator: it pushes the right-hand value
// into the left-hand stream and returns the stream, which is
// why you can chain more `<<` after it. `"hello"` is a string
// literal. `std::endl` is a special value meaning "write a
// newline character AND flush the buffer to the terminal".
// Why: Print the word `hello` followed by a newline.
// Gotcha: `<<` here is OPERATOR OVERLOADING — the same `<<` symbol is
// bitwise left-shift on integers. C++ lets a type redefine what
// an operator means. TS has no such mechanism, so do not expect
// to see `<<` used this way anywhere in TS.
//
// In TS you'd write (pseudocode):
// ```ts
// console.log("hello");
// ```
std::cout << "hello" << std::endl;
// What: `return 0;` ends the function and hands the value `0` back to
// whoever called it. For `main` specifically, the caller is the
// operating system, and `0` is the convention for "program
// succeeded".
// Why: Tell the OS the program finished without error.
//
// In TS you'd write (pseudocode):
// ```ts
// return 0;
// ```
return 0;
}
In this 4-line program the comments outweigh the code roughly 15:1.
**That
is the intended ratio.
** Other languages follow the same template by
analogy;
only the comment form changes:
a plain // / # / -- / ;
comment,
or the language's doc-comment form when the block sits above a
documentable declaration.
The lead-in stays In TS you'd write (pseudocode):
regardless of source language,
because the pseudocode block always contains
TypeScript.
If a real file feels too verbose, the answer is to make the file smaller (split into more functions, more files), not to thin out the comments.
These cases are taken from a real session where the skill was followed loosely. Each shows the bad output the agent produced and the good output the skill demands. Internalise the pattern, not just the specific construct.
Bad — the dum-dum block is written as plain // comments,
then a separate,
name-derived doc comment is bolted on only to satisfy a "every item needs a doc
comment" lint:
// What: `const CEILING: f32 = ...` is the -1 dBTP linear-amplitude ceiling.
// Why: Normalised output must never exceed it.
//
// In TS you'd write (pseudocode):
// ```ts
// const CEILING = 0.891;
// ```
/// Ceiling.
const CEILING: f32 = 0.8912509;
Good — the block itself is the doc comment (///),
so the one block both
satisfies the lint and documents the item;
there is no second summary:
/// What: `const CEILING: f32 = ...` is the -1 dBTP linear-amplitude ceiling.
/// Why: Normalised output must never exceed it.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const CEILING = 0.891;
/// ```
const CEILING: f32 = 0.8912509;
The /// Ceiling. line only restates the name and splits the documentation into
a real block plus a hollow summary.
For a statement inside a function body (not a
documentable item) the block stays plain //,
because a doc comment there is a
compile error.
Ok(rules) case)Bad — no comment on the function's tail expression because "it's just wrapping a value":
fn load_rules(path: &str) -> Result<Vec<Rule>, String> {
// ... body with comments ...
Ok(rules)
}
Good:
fn load_rules(path: &str) -> Result<Vec<Rule>, String> {
// ... body with comments ...
// What: `Ok(rules)` constructs the success variant of `Result`,
// wrapping our `Vec<Rule>`. No trailing `;` means this is
// the function's tail expression — Rust auto-returns it.
// Why: Hand the freshly loaded rules to the caller and signal
// "no error".
//
// In TS you'd write (pseudocode):
// ```ts
// return rules;
// ```
Ok(rules)
}
.to_string() case)Bad — .to_string() slipped in unexplained on a string literal:
return Err("no rules loaded".to_string());
Good:
// What: `Err("...".to_string())`. `Err` is the failure variant of
// `Result`. The literal `"no rules loaded"` has type
// `&'static str` — a borrowed slice of bytes baked into the
// binary at compile time. `.to_string()` allocates a fresh,
// OWNED `String` whose contents are copied from that slice.
// Why: The function signature is `Result<_, String>`, so the error
// channel must contain an owned `String`, not a borrowed
// `&str` — the caller may keep the error past our stack frame.
//
// In TS you'd write (pseudocode):
// ```ts
// throw new Error("no rules loaded");
// ```
return Err("no rules loaded".to_string());
Some(...) at function tail (the Some(escape_literal(trimmed)) case)Bad — silent because "it's obviously the return":
fn parse_rule_source(line: &str) -> Option<String> {
// ... body ...
Some(escape_literal(trimmed))
}
Good:
fn parse_rule_source(line: &str) -> Option<String> {
// ... body ...
// What: `Some(escape_literal(trimmed))` constructs the present
// variant of `Option`, wrapping the escaped string. Tail
// expression, so it's the return value.
// Why: The trimmed line is a plain literal; we escape it and
// hand it back as "yes, here is a rule source".
//
// In TS you'd write (pseudocode):
// ```ts
// return escapeLiteral(trimmed);
// ```
Some(escape_literal(trimmed))
}
.unwrap_or(false) case)Bad — silently appended to a method chain:
if !combined.is_match(&content).unwrap_or(false) {
return Ok(false);
}
Good:
// What: `combined.is_match(&content)` returns `Result<bool, RegexError>`.
// `.unwrap_or(false)` extracts the inner `bool` if the result
// is `Ok`, otherwise substitutes `false` and DROPS the error.
// `&content` borrows the bytes read-only — we are not
// transferring ownership to the matcher.
// Why: Treat any regex-engine failure as "no match" rather than
// propagating it; a corrupt input shouldn't crash the scan.
// Gotcha: `.unwrap_or(value)` on `Result` SILENTLY discards the error
// value. Use only when "no info, fall back" is genuinely
// correct.
//
// In TS you'd write (pseudocode):
// ```ts
// let matched: boolean;
// try { matched = combined.isMatch(content); } catch { matched = false; }
// if (!matched) return false;
// ```
if !combined.is_match(&content).unwrap_or(false) {
return Ok(false);
}
usize / String case)Bad — names usize and String without saying why these and not the
siblings:
// What: `struct Rule { ... }` with `index` (usize), `src` (String),
// `regex` (Regex).
// Why: We keep one Rule per forbidden-string entry.
struct Rule { index: usize, src: String, regex: Regex }
Good:
// What: `struct Rule { ... }` declares a record type with three OWNED
// fields:
// - `index: usize`. `usize` is the unsigned integer wide enough
// to address any byte in memory on this platform (32 bits on
// a 32-bit OS, 64 bits on a 64-bit OS). Siblings the reader
// might expect: `u32`, `u64`, `i32`, `i64`.
// - `src: String`. `String` is a heap-allocated growable UTF-8
// buffer that THIS struct owns. Sibling: `&str`, a borrowed
// view that doesn't own its bytes.
// - `regex: Regex`. An owned compiled regex object.
// Why: - `index` uses `usize` (not `u32`/`u64`) because every std
// API that takes a "size" or "index" wants `usize`; mixing
// widths forces casts everywhere.
// - `src` uses `String` (not `&str`) because the struct
// outlives the function that read the file; a borrowed slice
// would dangle.
// - `regex` is owned for the same outlive reason.
//
// In TS you'd write (pseudocode):
// ```ts
// type Rule = { index: number; src: string; regex: Regex };
// // TS has no owned/borrowed distinction (everything is GC'd), so the type-choice
// // question does not arise.
// ```
struct Rule { index: usize, src: String, regex: Regex }
<<,
::,
&,
*,
?,
!,
<...>,
mut,
lifetimes,
or any punctuation a
TS dev would not recognise,
name and explain each piece individually.Ok(rules),
Some(x),
(line, col),
if ... { a } else { b } at end of fn).
The
tail IS the return;
it always needs the full block.Some(...),
None,
Ok(...),
Err(...),
.to_string(),
.unwrap_or(...),
.ok(),
.clone(),
?) because it appeared a few
lines up.
Comment every recurrence until the user explicitly says
to stop.usize without "(not u32/u64/i64)";
String without "(not
&str)";
Box<T> without "(not Rc<T>/Arc<T>)".
The dum-dum reader
has no way to know a sibling exists.unique_ptr<T>").
Translate to TS-thinking instead.Why: does not say
what the program gains,
delete it and write a real one.This skill does not apply when:
.ts,
.tsx,
.js,
.jsx,
.mjs,
.cjs.html,
.css,
.scss,
.json,
.yaml,
.yml,
.toml,
.sql,
Dockerfile,
mise.toml,
package.json,
etc.DO NOT EDIT,
vendored from a third party)