소스 정보
- 저장소
- richlander/agent-cache-money
- 최근 소스 활동
- 2026년 7월 7일 01:27
- 감지된 SKILL.md 언어
- 영어
- 스타
- 0
- 포크
- 0
설치 방법
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
소스 파일 검토
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
메뉴
기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.
설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
직접 명령은 검토 Prompt를 거치지 않습니다. 실행하기 전에 소스를 확인하세요.
npx skills add https://github.com/richlander/agent-cache-money --skill markout명령은 한 줄로 유지됩니다. 복사하기 전에 가로로 스크롤해 전체 내용을 확인하세요.
로컬 사본을 원하시나요? SkillsMP에서 현재 제공할 수 있는 파일을 다운로드하세요.
SOC 직업 분류 기준
SKILL.md 표시 중
| name | markout |
| description | Markout serializer grounding (fixture). Use for Markout output questions. |
GROUNDING-CANARY: CANARY-CLAUDE-SKILL
Source-generated serializer. Default output is Markdown. Package Markout (includes the
source generator; no extra package needed).
using Markout;
// 1. Annotate every model type. List<T> -> table, scalar -> field.
[MarkoutSerializable(TitleProperty = nameof(Title))] // TitleProperty -> the H1 heading
public class Report
{
public string Title { get; set; } = "";
public int Count { get; set; }
[MarkoutSection(Name = "Items")] // -> "## Items" heading
public List<Row>? Items { get; set; } // List<T> -> a table
}
[MarkoutSerializable]
public class Row { public string Name { get; set; } = ""; public string Value { get; set; } = ""; }
// 2. Register EVERY type on a partial context (the source generator fills it in).
[MarkoutContext(typeof(Report))]
[MarkoutContext(typeof(Row))]
public partial class ReportContext : MarkoutSerializerContext { }
// 3. Serialize THROUGH the context.
MarkoutSerializer.Serialize(report, Console.Out, ReportContext.Default);
Serialize(obj) overload. EVERY MarkoutSerializer.Serialize
overload takes a MarkoutSerializerContext (or MarkoutTypeInfo<T>). Skipping the context does
not compile. This is the #1 mistake.[MarkoutSerializable] +
[MarkoutContext(typeof(T))] will not serialize. The context class MUST be partial.[MarkoutSerializable] (not
[JsonSerializable]), [MarkoutContext], [MarkoutSection(Name=...)], TitleProperty,
[MarkoutPropertyName], [MarkoutIgnore]. Do not use Json* attributes.List<T> -> table; scalar (string/int/bool) ->
a Field | Value row; [MarkoutSection(Name="X")] -> a ## X heading above the property.[MarkoutIgnoreInTable] on non-tabular list properties (List<Metric>, List<Breakdown>,
List<TreeNode>, List<Description>, Callout) or they get mistreated as table columns.Metric (bar chart), Breakdown/Slice (stacked bar), Callout (alert), TreeNode
(hierarchy), Description (term + text), CodeSection (code block). e.g. new Metric("Build", 4.2).
Pass children as a list/array/collection expression, never as trailing arguments:
new TreeNode("root", [new TreeNode("leaf")]). Badge is an optional property:
new TreeNode("root") { Badge = "📁" }.
Composite cells are data-only scalar properties: FieldLayout.Table renders a dense Markdown
value, and TableFormatter (TSV/JSONL) decomposes each into typed columns from one declaration.
Change<V> — a before → after change (NOT Comparison, which collides with System.Comparison<T>).
[MarkoutDelta(Delta.Percent)] on a numeric Change<V> appends the signed change, e.g.
98555 → 61190 (−38%); Delta.Absolute appends the signed difference; Delta.Multiple appends a
multiplicative factor with a direction word, e.g. 15 → 5 (3× fewer) / 5 → 15 (3× more) (a zero
endpoint renders —). With a goal, an aligned Delta.Multiple word omits the redundant status word
(15 → 5 (3× fewer) under Goal.Lower); a conflicting one keeps it (5 → 15 (3× more, bad)).
[MarkoutDeltaNoun("solved")] renders a caller noun on the signed delta —
4/6 → 6/6 (+2 solved) (sibling of [MarkoutUnit]; composites use IDeltaCountable: Fraction→count,
Share→value; Markdown-only).
[MarkoutGoal(Goal.Higher)] / [MarkoutGoal(Goal.Lower)] on a numeric Change<V> makes Markout
derive two decomposed fields — a structural direction
(increased/decreased/introduced (0→N)/resolved (N→0)/unchanged) and a goal-applied polarity
status (good/bad/neutral) — instead of the caller hand-coding ceiling/floor/drift. Optional
noise, [MarkoutGoal(Goal.Higher, 0.001)], treats sub-threshold movement as unchanged. Goal.Context
(default) derives nothing. Composite Change<Share|Percent|Fraction> also derive direction/status
from a single comparable magnitude (Share → raw Value; Percent/Fraction → their ratio;
Segments → the sum of its parts' values, i.e. the breakdown total). In dense Markdown the polarity word
renders inline, merged with any delta suffix into one group: , .JSONL decomposition is heterogeneous (each record holds only its own keys); TSV keeps a uniform
column union (absent cells blank). Set MarkoutWriterOptions.JsonTypedValues = true to emit numeric
columns as JSON numbers instead of strings.
When a composite cell (Change<V>, etc.) is a column of an element table (List<T> where T has a
composite property), structured formatters (TSV/JSONL) decompose it into typed {column}_{sub} columns
— score_before/score_after/score_delta_pct, bugs_direction/bugs_status, tasks_delta_count/
tasks_delta_noun — so the card is reconstructable from the data. Markdown keeps the dense cell
(100 → 50 (-50%)). Scalar columns and Markdown are unchanged. [MarkoutIgnoreColumnWhen] columns that
are hidden for the table are dropped from the decomposed output too.
Two list-shapes render as multi-format cards from a [MarkoutSerializable] model — Markdown table +
flat typed JSONL/TSV — with no imperative writer calls:
List<MetricChange<T>> — a gated scalar metric per row. MetricChange<T>(Name, Before, After, Target? = null, TargetLabel? = null, Status = GateStatus.Unknown, StatusLabel? = null) where
T : struct. Set { Goal = Goal.Higher|Lower } (init property; optionally Noise) to derive the
direction/status axes from Before → After; a caller-supplied Status overrides the derived
polarity. Dense Markdown (default): Metric | Change | Target with the status word inlined
(0 → 7 (bad) — caller StatusLabel wins over the slug) and a goal marker on the label
(Failures (-) / Fully raised (+)); the Status column is dropped. Set
MarkoutWriterOptions.InlineGoalStatus = false for the legacy Metric | Change | Target | Status.
JSONL/TSV are unaffected: flat before/after/optional target/target_label/direction/status.
T must be a numeric scalar (int/long/double/decimal/...); a composite T (e.g. Segments) is a
compile error (MARKOUT005).[MarkoutSection(Name = "...", IncludeSectionInStructuredRows = true)] on a List<MetricChange<T>>
or List<MultiSourceRow> section prepends a leading section column (the section name) to TSV/JSONL
rows — for multiplexing several sectioned card shapes into one structured stream. Markdown is unchanged.List<MultiSourceRow> — a role matrix: MultiSourceRow(label, params Source[]),
Source(role, IMarkoutCell? value, format = default). Roles pivot to columns in Markdown
(caller-supplied order; absent role → -); JSONL emits one flat record per row with
{role}_{side}_{field} keys. Values are any IMarkoutCell incl. nested Change<Share> etc.;
scalars work too — new Source("baseline", 2) (int/long/double/decimal) and Source.Text(role, s)
decompose to a single field; is an absent cell. Set the label column
header with (defaults to ).Decomposition keys are snake_case_lower (a fused role like claude-opus-4.8 becomes
claude_opus_4_8_...). Put [MarkoutIgnoreInTable] on these lists only when nested inside a table.
Pass a formatter to change output: new MarkdownFormatter() (default), PlainTextFormatter,
UnicodeFormatter, TableFormatter (compact/TSV/JSONL via MarkoutWriterOptions.TableMode).
e.g. MarkoutSerializer.Serialize(report, Console.Out, new TableFormatter(), ReportContext.Default);
0 → 7 (bad)98555 → 61190 (−38%, good)Fraction(count, total) → 24/24; Share(value, whole) → 5056 (24%)
([MarkoutUnit("s")] → 103s (93%)); Percent(part, whole) → 93%;
Segments(new Segment(label, value), ...) → 21/171/236 (labels become column names).Change<V> nests over composites: Change<Fraction>, Change<Share>, Change<Segments>.
A zero denominator renders — rather than NaN/Inf. e.g.
[MarkoutPropertyName("Session IET"), MarkoutDelta(Delta.Percent)] public Change<long> SessionIet { get; init; }.{role}new Source(role, null)[MarkoutLabelHeader("Metric")]FieldVerdict(GateStatus Status, string? Label = null) — a first-class verdict cell (typed polarity
GateStatus + optional caller label); use as a Source value for a verdict row (decomposes to {role}).