Argano の鈴木です。 Claude Code で利用できる、出力形式の設定機能について紹介します。

はじめに

Argano 社内でも、設計の壁打ちやコーディング、コードレビューなど、開発のさまざまな場面で AI を使うことが当たり前になってきました。

便利な一方で、AI が出力する文章を読む量と時間が増えました。最近はその文章を読むことに負担を感じています。 負担になっている理由として、まず思い当たるのは、出力される文章の全体的な量が多いことです。

そのなかで、Claude Code にはoutput style(出力スタイル)という、出力スタイルを調整できる機能があることを知りました。 AI からの出力形式を調整すれば、読む負担を抑えられるのではないかと思ったので、Claude Code の output style 機能を試していきます。

出力スタイルとは

Claude Code にはデフォルトのスタイル + 4つの組み込みのスタイルが用意されており、さらに独自のスタイルを作成できます。

  • Default

スタイルの指示を追加しない標準の状態です。

  • Proactive

依頼を受けたらすぐ実装に入り、日常的な判断は質問せずに進めます。

  • Concise

最初の1文で結果や答えを述べ、前置きや経過の説明、末尾の要約を省きます。単純な質問には1〜3文で答えます。

  • Explanatory

Default と同じ進め方で、選択の理由を Insight ブロックとして会話内に添えます。ファイルのコメントには書かれません。Default より出力は長くなります。

  • Learning

Explanatory と同じ Insight に加えて、設計判断を伴う部分を TODO(human) として残し、ユーザーがコードを書くまで待ちます。

Default、Concise、Explanatory と、自作するカスタムスタイルを加えた4つの出力スタイルの違いをこの記事では取り上げて紹介します。

Proactive は、質問せずに進めるかどうかを変えるだけで、説明の文体や構成は変わりません。読む負担の比較とは関係がないため、対象外とします。 Learning は、出力の読みやすさを比べる際に「待つ・書く」という別の要素が混ざるため、対象外としました。Explanatory と共通する Insight の部分は、Explanatory で確認します。

環境

今回使用した各種バージョン・モデルは以下になります。

  • Claude Code: 2.1.321
  • model: Sonnet 5.5
  • effort: medium

試した方法

CLAUDE.md の記載内容に影響を受ける可能性があるため、一時的に ~/.claude/CLAUDE.md を空にした状態で試します。

Default / Concise / Explanatory / カスタム出力スタイル の4パターンをそれぞれoutput-styleに設定し、独立したセッションで以下の質問文をプロンプトに投げて回答させます。

JavaScript の Promise.all と Promise.allSettled の違いと使い分けを教えて

また、出力内容に不足がないかをチェックするために、以下についての言及があるかをチェックします。

  • Promise.all は、1つでも reject されると全体が reject される。成功済みの結果は受け取れない
  • Promise.allSettled は reject せず、各要素が {status: ‘fulfilled’, value} または {status: ‘rejected’, reason} になる
  • 使い分けの基準。すべて成功が前提なら all、個別の成否が必要なら allSettled

カスタム出力スタイルの作成

回答を3行にまとめて出力させるカスタム出力スタイルを作成してみます。 AIの出す文章量を負担に感じていたため、3行でも分かりやすい文章が出力されれば読む文章量を一気に減らせるのではないかと期待しています。

作業用ディレクトリに以下の内容で .claude/output-styles/three-lines.md を作成し、Claude Code上から設定します。

---
name: Three lines
description: 回答を3行以内に収める
keep-coding-instructions: true
---

回答は、必ず3行以内の文章で出力します。

- 1行は、改行で区切られた1文または1文節とします。
- 表、箇条書き、見出し、コードブロックは使いません。
- 前置き、経過の説明、末尾の要約は書きません。

フロントマターの keep-coding-instructions は、Claude Code 標準のソフトウェアエンジニアリング向け指示(変更範囲の決め方、コメントの書き方、作業の検証など)を残すかどうかを指定する項目です。デフォルトは false で、カスタム出力スタイルを使うとこの指示が外れます。今回はコーディングの質問に答えさせる比較なので true にして、標準の指示を残したまま回答形式だけを3行に変えています。

試した結果

※ 以降の出力に含まれる罫線の表は、レイアウトの都合で記事用の表に置き換えて掲載しています。

Default

Promise.all と Promise.allSettled の違い

挙動の違い
Promise.allPromise.allSettled
成功条件全てが fulfilled常に fulfilled(reject しない)
失敗時1つでも reject されたら即座に reject(最初のエラーのみ)全ての完了を待ち、各結果を返す
戻り値値の配列{status, value / reason} の配列
速度fail-fast(失敗時は早く返る)最も遅い Promise まで待つ
const ps = [
  Promise.resolve(1),
  Promise.reject(new Error('NG')),
  Promise.resolve(3),
];

await Promise.all(ps);
// → Error: NG をスローする(1, 3 の結果は取れない)

await Promise.allSettled(ps);
// → [
//   { status: 'fulfilled', value: 1 },
//   { status: 'rejected',  reason: Error('NG') },
//   { status: 'fulfilled', value: 3 },
// ]

使い分け

Promise.all を使う場面

全部成功して初めて意味がある処理(all-or-nothing)。

- 画面描画に必要な複数 API(ユーザー情報+設定+権限)を並列取得
- 依存する初期化処理を並列実行
- 1つ失敗したら全体を失敗扱いにして早く打ち切りたい

const [user, settings] = await Promise.all([
  fetchUser(id),
  fetchSettings(id),
]);

Promise.allSettled を使う場面

個別の成功・失敗を区別して処理を続けたいとき(部分成功を許容)。

- 複数ファイルの一括アップロードで、成功/失敗を個別に報告
- 複数サービスへの通知送信(一部失敗しても他は継続)
- ダッシュボードの各ウィジェットを独立して取得(失敗したものだけエラー表示)

const results = await Promise.allSettled(files.map(upload));

const succeeded = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed    = results.filter(r => r.status === 'rejected').map(r => r.reason);

注意点

- Promise.all は他の Promise をキャンセルしない。1つ reject されても残りの処理は裏で動き続けます。副作用のある処理(書き込み等)では注意が必要です。
- Promise.all の未処理エラー:最初の reject 以降の reject は握りつぶされ、unhandledrejection にはなりません。
- allSettled は自動でエラーを検知してくれないため、rejected を自分でチェックしないと失敗を見逃します。
- 補足:最初に成功したものだけ欲しい → Promise.any、最初に完了したもの → Promise.race。

判断の目安

▎ 「1つでも失敗したら全体が無意味か?」
▎ - Yes → Promise.all
▎ - No(個別に結果を扱いたい) → Promise.allSettled
  • チェック項目は 3/3 クリア
  • 表を用いて、基本的な使い方の違いを解説している
  • 全体で72行
  • 要点は冒頭の比較表に、使い分けの結論は末尾にある
  • unhandledrejection など、説明のない用語がある

Concise

違い: Promise.all は1つでも reject されると即座に reject し、全部成功したときだけ値の配列を返します。Promise.allSettled は reject されず、全部の完了を待って {status, value|reason} の配列を返します。

await Promise.all([Promise.resolve(1), Promise.reject('x')]);
// → reject('x')(最初の失敗理由だけ)

await Promise.allSettled([Promise.resolve(1), Promise.reject('x')]);
// → [{status:'fulfilled', value:1}, {status:'rejected', reason:'x'}]

使い分け
- all: 全部成功しないと意味がない場合(例: 画面描画に必要なAPIを並列取得)。1つ失敗した時点で全体を失敗扱いにできます。
- allSettled: 個別の成否を見て処理を続けたい場合(例: 複数ファイルのアップロードで、失敗したものだけ再試行)。

エッジケース
- all が reject しても、他の Promise はキャンセルされず実行され続けます。
- 空配列では、all は [] で resolve し、allSettled も [] で resolve します。
- Promise 以外の値は、そのまま fulfilled として扱われます。
- 結果の順序は完了順ではなく、入力順です。
  • チェック項目は 3/3 クリア
  • 冒頭の1文で、違いの要点を述べている
  • 表は使っていない
  • 全体で17行
  • Default との違いは次のとおり
    • Default では使い分けの結論(「判断の目安」)が末尾にあるが、Concise にはその節がない
    • 使い分けの要点が、例を1つずつ添えた2項目の箇条書きに収まっている
    • 速度の比較、Promise.any / Promise.race の補足、未処理エラーと結果確認の注意、各場面のコード例を省いている
    • Default にはない「エッジケース」(空配列、Promise 以外の値、結果の順序)が加わっている

Explanatory

★ Insight ─────────────────────────────────────
- Promise.all は「1つでも失敗したら全体が失敗する」(fail-fast)、Promise.allSettled は「全部の結果が出るまで待つ」という違いです。
- 判断基準は、各タスクが全部成功しないと意味がないか、部分的な成功でも使えるかです。
  ─────────────────────────────────────────────────

基本的な違い
Promise.allPromise.allSettled
解決条件すべて fulfilledすべて settled(成功・失敗問わず)
失敗時最初の reject で即座に rejectreject しない(常に fulfilled)
戻り値値の配列{status, value / reason} の配列
導入ES2015ES2020
コード例

const tasks = [
  fetch('/api/user'),
  fetch('/api/posts'),
  Promise.reject(new Error('失敗')),
];

// Promise.all: 1つ失敗した時点で catch へ
try {
  const results = await Promise.all(tasks);
} catch (e) {
  console.log(e.message); // "失敗"(他の成功結果は取得できない)
}

// Promise.allSettled: 全部の結果を受け取れる
const results = await Promise.allSettled(tasks);
// [
//   { status: 'fulfilled', value: Response },
//   { status: 'fulfilled', value: Response },
//   { status: 'rejected',  reason: Error('失敗') },
// ]

const succeeded = results.filter(r => r.status === 'fulfilled').map(r => r.value);
const failed    = results.filter(r => r.status === 'rejected').map(r => r.reason);

使い分け

Promise.all が向くケース
- すべてが揃わないと次に進めない処理です(例: 画面描画に必要な複数 API をまとめて取得する)。
- 1つの失敗を全体の失敗として扱いたい場合です。
- 早く失敗を検知して、すぐエラー処理に移りたい場合です。

Promise.allSettled が向くケース
- 部分的な成功でも価値がある処理です(例: ダッシュボードの各ウィジェットを個別に読み込む)。
- 複数のファイルアップロードや一括処理で、成功・失敗を個別に集計したい場合です。
- 通知の一斉送信など、失敗を記録しつつ残りを継続したい場合です。

注意点

1. Promise.all は失敗後も他の Promise を止めません。 最初の reject で all 自体は reject されますが、残りの処理はバックグラウンドで走り続けます。キャンセルしたい場合は AbortController が必要です。
2. reject が拾われない問題。 Promise.all の2つ目以降の reject は握りつぶされるため、ログに残りません。全エラーを把握したいなら allSettled を使います。
3. allSettled はエラーが例外にならない。 reason を自分でチェックしないと、失敗に気づかずに進んでしまいます。
4. 似た仲間もあります。
   - Promise.race: 最初に settle したものを採用します。タイムアウト実装などに使います。
   - Promise.any: 最初に fulfill したものを採用します。全部失敗すると AggregateError になります。冗長なミラーサーバーへのリクエストなどに向きます。

選び方の目安

▎ 「1つでも失敗したら、他の結果は不要か?」
▎ → Yes なら all、No(他の結果も使いたい)なら allSettled

★ Insight ─────────────────────────────────────
- TypeScript では allSettled の結果が PromiseSettledResult<T> という判別共用体になります。r.status === 'fulfilled' で絞り込むと、r.value に型安全にアクセスできます。
- フィルタ時は型ガードを書くと便利です: .filter((r): r is PromiseFulfilledResult<T> => r.status === 'fulfilled')
  ─────────────────────────────────────────────────
  • チェック項目は 3/3 クリア
  • 全体で75行
  • 丁寧に説明されている
  • 冒頭の Insight に、違いと判断基準が先に書かれている。末尾の「選び方の目安」と内容が重なり、結論が2回出ている
  • 説明のない用語が新たに増えている
    • AggregateError、AbortController、判別共用体、型ガードなど

カスタム出力スタイル

Promise.all は1つでも reject されると即座に rejectされ、全て成功した場合のみ結果の配列を返します。
Promise.allSettled は全ての Promise の完了を待ち、各結果を {status, value/reason} の配列で返し、決して reject されません。
全て成功が前提で1つの失敗で処理を止めたいならall、失敗を許容して個別に成否を扱いたいなら allSettled を使います。
  • チェック項目は 3/3 クリア(1つ目の「成功済みの結果は受け取れない」は、「全て成功した場合のみ結果の配列を返します」という表現で示されている)
  • 3行に収まり、前置きや末尾の要約はない。1〜2行目に違いの要点、3行目に使い分けの基準がある
  • コード例、具体的な場面(画面描画、通知など)、注意点(キャンセルされない、結果の確認を忘れない)がすべて消えた。使い分けの記述が抽象的になり、実際に使う場面を思い描きにくい

まとめ

AI からの出力形式を調整すれば、読む負担を抑えられるのではないか

「はじめに」で挙げたこの見立てについては、出力スタイルで文章量は減らせましたが、その分、省かれる情報も出ました。 各スタイルを試した結果を振り返ります。

  • Concise(17行)と3行のカスタムスタイルは、Default(72行)より文章量を大きく減らせた
  • 短くしても、チェック項目は4パターンすべてで満たされた
  • 短い出力で省かれたのは、Concise では各場面のコード例や一部の注意点、カスタムではコード例・具体的な場面・注意点のすべてだった。こうした情報を取り出せるかは、追加の質問などプロンプト次第である
  • Explanatory は、冒頭の Insight で結論が先に読める。一方で、行数は Default とほぼ同じ75行で、説明のない用語が増え、結論も2回出た
    • 丁寧に書かれることと、読みやすいことは別という感想を持った

あくまで筆者の感想ですが、読む負担に影響するのは、文章量と、結論の位置や重複といった構成だと感じました。 今回の範囲(コードを書かせない概念質問、各1回)では、概要をつかみたいときは文章量を抑えるスタイルが向いている印象で、具体例や注意点まで必要なときは Default や Explanatory が向いていそうです。

チェック項目を満たしたまま、出力が Default の72行から17行へ減り、冒頭の1文で違いの要点がつかめて読む量が減ったので、個人的には Concise をこれからも使っていきたいと感じました。 省かれた情報は、必要な場面で質問して補えばよいと考えています。

これからもカスタムスタイルやプロンプトを調整したり、skills を組み合わせるなどして、さらに読みやすい出力になるようにいろいろ試していきたいです。

参考文献

https://code.claude.com/docs/en/output-styles